/* ==========================================================================
   LIENZO — sistema de diseño de Plataforma para Eventos
   Implementación canónica de la spec 20. Reemplaza a "Ácido" (2026-08-26).

   Dos reglas antes de tocar este archivo:
   1. Los nombres de clase NO cambian. 3 300 usos en el frontend dependen de
      ellos; acá cambia el aspecto, nunca la API.
   2. Ningún componente escribe un color, un radio ni una sombra literal:
      todo sale de un token, y el token es lo único que sabe de temas.
   ========================================================================== */

/* ---------- Tokens ----------
   Tres estados del tema, y los tres tienen que resolver completos: sin
   `data-theme` (el sistema decide), `light` y `dark`. El bloque base define el
   tema CLARO —el default— y los otros dos solo redefinen tokens. */
:root, :root[data-theme="light"] {
  --bg: #f4f6fb;            /* el lienzo */
  --surface: #ffffff;       /* tarjetas, paneles, modales */
  --surface-2: #f8fafc;     /* zonas suaves: thead, zebra, campos */
  --surface-3: #eef1f7;     /* hover de superficie suave */
  --ink: #0f172a;
  --ink-2: #334155;
  --mut: #64748b;
  --line: #e4e8f0;
  --line-2: #cbd5e1;        /* borde de control en reposo */

  --acc: #3557f0;           /* acento como texto y borde */
  --acc-fill: #3557f0;      /* acento como relleno */
  --acc-ink: #ffffff;       /* tinta sobre el relleno */
  --acc-soft: #eef2ff;      /* fondo suave: hover, seleccionado */
  --acc-2: #7c5cf0;         /* segundo tono del degradado destacado */

  --ok: #0e9f6e;   --ok-bg: #e7f8f1;
  --warn: #b45309; --warn-bg: #fdf3e7;
  --bad: #dc2626;  --bad-bg: #fdeced;

  /* Paleta de DATOS (spec 20 §5): independiente del acento y siempre en este
     orden, para que dos gráficos de la misma pantalla no repitan color. */
  --d1: #4f6cf7; --d2: #0ea5a5; --d3: #22c55e;
  --d4: #8b5cf6; --d5: #f59e0b; --d6: #f43f5e;

  --ref: rgba(53, 87, 240, .06);      /* columna de referencia (.comp) */
  --ref-line: rgba(53, 87, 240, .35);
  --chart-track: #eef1f7;
  --row-alt: #fafbfd;

  --r: 12px;                /* superficies */
  --r-sm: 8px;              /* controles */
  --sh-1: 0 1px 2px rgba(15, 23, 42, .04), 0 2px 8px rgba(15, 23, 42, .06);
  --sh-2: 0 12px 32px rgba(15, 23, 42, .14);

  --body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --display: var(--body);
  --h-weight: 700;

  /* Espaciado — escala base 4px (spec 30 §1). Nada de .35rem sueltos. */
  --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-8: 3rem;

  /* Velos de volumen — el sombreado de las caras del objeto 3D de la puerta.
     Son UN mecanismo para las dos variantes (cara neutra y cara con acento) y
     para los dos temas: la cara se pinta con su color de base y encima le cae
     el velo que le toca según hacia dónde mira. Así la luz viene siempre del
     mismo lado, que es lo que hace que un prisma se lea como sólido y no como
     tres rectángulos pegados. En claro la cara de arriba no lleva velo —el
     blanco ya es lo más claro que hay—; en oscuro se le pone uno blanco. */
  /* Panel de marca de la puerta (spec 08 §1): es oscuro SIEMPRE, en los dos
     temas, porque es una superficie de marca y no una superficie de la app.
     Sus valores viven acá como tokens; adentro del panel se remapean los
     genéricos, así lo que se dibuje ahí (el objeto 3D incluido) sale bien sin
     un solo color suelto. */
  --marca-bg: #0b1020;      /* fondo del panel: casi negro con sesgo al acento */
  --marca-bg-2: #141b3a;    /* el resplandor de la esquina */
  --marca-ink: #f2f5ff;
  --marca-mut: #97a3c7;
  --marca-line: rgba(255, 255, 255, .12);
  --marca-surface: #161d33;
  --marca-surface-2: #1b2340;
  --marca-surface-3: #222c4f;
  /* El acento COMO TEXTO sobre el panel: el de tema claro daba 3.40:1 medido
     sobre `--marca-bg` —pasa raspando como texto grande y falla en cualquier
     otro tamaño—. Este es el mismo tono que el sistema ya usa en oscuro. */
  --marca-acc: #7e9bff;

  --vol-tapa: transparent;               /* cara superior: la que recibe la luz */
  --vol-frente: rgba(15, 23, 42, .09);   /* cara frontal: media sombra */
  --vol-lado: rgba(15, 23, 42, .21);     /* cara lateral: la más oscura */
  --vol-piso: rgba(15, 23, 42, .14);     /* la sombra que el objeto deja en el suelo */

  /* Escala de capas (spec 21). Existe porque los z-index se venían eligiendo a
     ojo, y así fue como el desplegable del buscador de contactos (70) terminó
     DETRÁS del modal (100): el resultado existía, se podía elegir con el
     teclado, y no se veía.

     La regla que ordena la escala: **lo que puede nacer DENTRO de un modal va
     por encima del modal**, y un aviso siempre gana — un `toast` que no se ve
     no es un aviso. */
  --z-sticky: 20;     /* barras pegadas dentro del contenido */
  --z-barra: 40;      /* barra superior */
  --z-menu: 60;       /* menús colgados de la barra: nunca nacen en un modal */
  --z-scrim: 70;      /* velo del riel en móvil */
  --z-rail: 80;       /* el riel en móvil */
  --z-modal: 100;     /* el velo del modal */
  --z-flotante: 200;  /* desplegables que SÍ pueden nacer dentro de un modal */
  --z-pantalla: 300;  /* capas a pantalla completa por encima del modal */
  --z-toast: 400;     /* siempre lo más alto */

  --control-h: 38px;

  --t-fast: 150ms ease-out;
  --t-med: 220ms ease-out;
  --t-slow: 420ms ease-out;

  color-scheme: light;
}

/* El sistema en oscuro cuando nadie eligió, y la elección explícita. Se listan
   los dos selectores juntos: separarlos es como se termina con un tema a
   medias que solo aparece en la máquina de alguien. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0f1117;
    --surface: #171a23;
    --surface-2: #1c2029;
    --surface-3: #232836;
    --ink: #e8ecf5;
    --ink-2: #c2cadb;
    --mut: #94a3b8;
    --line: #262c39;
    --line-2: #364155;
    --acc: #7e9bff;
    /* Calibrados con el medidor, no a ojo: `#4f6cf7` con tinta casi negra daba
       4.39:1 y el segundo tono del degradado con blanco, 3.12:1 — los dos por
       debajo de AA. Sobre un relleno saturado la tinta es blanca en LOS DOS
       temas, y el relleno oscuro baja hasta que el blanco llegue a 5.37:1. */
    --acc-fill: #3f5ce8;
    --acc-ink: #ffffff;
    --acc-soft: rgba(126, 155, 255, .14);
    --acc-2: #7d5cf5;
    --ok: #34d399;   --ok-bg: rgba(52, 211, 153, .14);
    --warn: #fbbf24; --warn-bg: rgba(251, 191, 36, .14);
    --bad: #f87171;  --bad-bg: rgba(248, 113, 113, .14);
    --ref: rgba(126, 155, 255, .08);
    --ref-line: rgba(126, 155, 255, .45);
    --chart-track: #232836;
    --row-alt: #1b1f28;
    --sh-1: 0 1px 2px rgba(0, 0, 0, .4);
    --sh-2: 0 16px 40px rgba(0, 0, 0, .55);
    /* En oscuro la superficie ya es oscura: la cara de arriba se ACLARA con un
       velo blanco, y las otras dos siguen oscureciéndose. Misma luz, mismo
       lado; lo que cambia es desde dónde se parte. */
    --vol-tapa: rgba(255, 255, 255, .07);
    --vol-frente: rgba(0, 0, 0, .24);
    --vol-lado: rgba(0, 0, 0, .44);
    --vol-piso: rgba(0, 0, 0, .55);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg: #0f1117;
  --surface: #171a23;
  --surface-2: #1c2029;
  --surface-3: #232836;
  --ink: #e8ecf5;
  --ink-2: #c2cadb;
  --mut: #94a3b8;
  --line: #262c39;
  --line-2: #364155;
  --acc: #7e9bff;
  --acc-fill: #3f5ce8;
  --acc-ink: #ffffff;
  --acc-soft: rgba(126, 155, 255, .14);
  --acc-2: #7d5cf5;
  --ok: #34d399;   --ok-bg: rgba(52, 211, 153, .14);
  --warn: #fbbf24; --warn-bg: rgba(251, 191, 36, .14);
  --bad: #f87171;  --bad-bg: rgba(248, 113, 113, .14);
  --ref: rgba(126, 155, 255, .08);
  --ref-line: rgba(126, 155, 255, .45);
  --chart-track: #232836;
  --row-alt: #1b1f28;
  --sh-1: 0 1px 2px rgba(0, 0, 0, .4);
  --sh-2: 0 16px 40px rgba(0, 0, 0, .55);
  /* En oscuro la superficie ya es oscura: la cara de arriba se ACLARA con un
     velo blanco, y las otras dos siguen oscureciéndose. Misma luz, mismo
     lado; lo que cambia es desde dónde se parte. */
  --vol-tapa: rgba(255, 255, 255, .07);
  --vol-frente: rgba(0, 0, 0, .24);
  --vol-lado: rgba(0, 0, 0, .44);

}

/* ---------- Base ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: .94rem/1.55 var(--body);
  -webkit-font-smoothing: antialiased;
  transition: background var(--t-fast), color var(--t-fast);
}
[data-num], .num { font-variant-numeric: tabular-nums; }
::selection { background: var(--acc-soft); color: var(--ink); }

* { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 999px; border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--mut); background-clip: content-box; }

:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; border-radius: var(--r-sm); }

a { color: var(--acc); text-decoration: none; transition: color var(--t-fast); }
a:hover { color: var(--acc); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- Topbar ----------
   Era una banda de color saturado; ahora es una superficie más. La barra
   superior de una herramienta de trabajo no compite con el contenido. */
.topbar {
  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-3) var(--sp-5);
  background: var(--surface); color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.topbar .logo { font-weight: 700; letter-spacing: -.02em; color: var(--ink); display: flex; align-items: center; gap: var(--sp-2); }
.topbar .logo img { height: 22px; display: block; }
.topbar nav { display: flex; gap: var(--sp-1); font-size: .88rem; }
.topbar nav a {
  color: var(--mut); font-weight: 500; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm); transition: background var(--t-fast), color var(--t-fast);
}
.topbar nav a:hover { color: var(--ink); background: var(--surface-2); text-decoration: none; }
.topbar nav a.on { color: var(--acc); background: var(--acc-soft); }
.topbar .user { margin-left: auto; font-size: .84rem; color: var(--mut); }

/* ---------- Layout ---------- */
.page { padding: var(--sp-5); display: grid; gap: var(--sp-5); max-width: 1240px; margin: 0 auto; }
.page-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.page-head h1, .page-head h2 {
  margin: 0; font-family: var(--display);
  font-size: 1.6rem; font-weight: var(--h-weight);
  letter-spacing: -.02em; line-height: 1.2;
}
/* El sufijo `↗` de Ácido se retira: era la firma de aquel sistema. */
.page-head h1::after, .page-head h2::after { content: none; }

/* Chip de estado del sistema. */
.sys {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: .74rem; font-weight: 600;
  padding: .2rem .6rem; border-radius: 999px;
  background: var(--acc-soft); color: var(--acc);
}

/* ---------- KPIs ---------- */
.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-4); }
.kpi {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: var(--sp-4) var(--sp-4) var(--sp-3);
  box-shadow: var(--sh-1);
  transition: box-shadow var(--t-fast), transform var(--t-fast);
}
.kpi:hover { box-shadow: var(--sh-2); transform: translateY(-1px); }
/* El destacado es la tarjeta con degradado de la referencia: una por pantalla,
   nunca dos — deja de destacar en cuanto se repite. */
.kpi.destacado, .kpi.destacado:hover {
  background: linear-gradient(135deg, var(--acc-fill), var(--acc-2));
  border-color: transparent; color: var(--acc-ink);
}
.kpi.destacado .k-label, .kpi.destacado .k-note { color: color-mix(in srgb, var(--acc-ink) 78%, transparent); }
.kpi.destacado .k-value { color: var(--acc-ink); }
.kpi .k-label { font-size: .74rem; font-weight: 600; color: var(--mut); letter-spacing: .02em; }
.kpi .k-value { font-size: 1.9rem; font-weight: 700; letter-spacing: -.03em; margin-top: var(--sp-1); font-variant-numeric: tabular-nums; }
.kpi .k-note { font-size: .78rem; color: var(--mut); margin-top: var(--sp-1); }
.kpi .up { color: var(--ok); font-weight: 600; }
.kpi .down { color: var(--bad); font-weight: 600; }

/* ---------- Paneles ---------- */
.panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--sh-1); overflow: hidden;
}
.panel > header {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  font-size: .94rem; font-weight: 600; color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.panel > header .info { margin-left: auto; font-size: .78rem; font-weight: 400; color: var(--mut); }
.p-pad { padding: var(--sp-4); }

/* ---------- Tablas ----------
   El encabezado era tinta invertida con filo de acento; ahora es una zona
   suave con etiquetas en minúscula alta. Lo que separa la cabecera del dato es
   el fondo y el peso, no un bloque de color. */
.table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.table thead th, .comp thead th {
  background: var(--surface-2); color: var(--mut);
  text-align: left; font-size: .72rem; font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
  padding: var(--sp-3) var(--sp-4); white-space: nowrap;
  border-bottom: 1px solid var(--line);
}
.table th.num, .table td.num, .comp th.num { text-align: right; width: 1%; font-variant-numeric: tabular-nums; }
.table td { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line); color: var(--ink-2); }
.table tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background var(--t-fast); }
.table tbody tr:nth-child(even) td { background: var(--row-alt); }
.table tbody tr:hover td { background: var(--acc-soft); }
.table .rank { color: var(--mut); font-variant-numeric: tabular-nums; }
.table tr.first .rank { color: var(--acc); font-weight: 700; }
.table tfoot td, .table tr.total td {
  border-top: 1px solid var(--line-2); font-weight: 700; color: var(--ink);
  background: var(--surface-2);
}
.table thead th.ord { cursor: pointer; user-select: none; }
.table thead th.ord .ord-ind { opacity: 0; margin-left: var(--sp-1); transition: opacity var(--t-fast); }
.table thead th.ord:hover .ord-ind { opacity: .5; }
.table thead th.ord.asc .ord-ind, .table thead th.ord.desc .ord-ind { opacity: 1; color: var(--acc); }
.table thead th { position: relative; }
.table thead th .col-resize {
  position: absolute; top: 0; right: 0; width: 6px; height: 100%;
  cursor: col-resize; background: transparent; transition: background var(--t-fast);
}
.table thead th .col-resize:hover, .table thead th .col-resize.activo { background: var(--acc); }
.table.redim td, .table.redim th { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Arrastre de filas y secciones (grids editables). */
.drag-handle { cursor: grab; color: var(--mut); opacity: 0; transition: opacity var(--t-fast), color var(--t-fast); }
tr:hover .drag-handle, .sec:hover .drag-handle { opacity: 1; }
.drag-handle:hover { color: var(--acc); }
.drag-handle:active, .arrastrando .drag-handle { cursor: grabbing; color: var(--acc); }
tr.arrastrando, .sec-arrastrando { opacity: .45; }
tr.drop-target > td { box-shadow: inset 0 2px 0 var(--acc); }
tr.drop-target-abajo > td { box-shadow: inset 0 -2px 0 var(--acc); }
.sec-drop-target { box-shadow: inset 0 2px 0 var(--acc); }
.table th.dragcol, .table td.dragcell { width: 1%; padding-left: var(--sp-2); padding-right: 0; }
.table .sec + .sec { border-top: 1px solid var(--line); }

/* ---------- Grid editable (estilo lista) ---------- */
.t-input {
  width: 100%; background: transparent; border: 1px solid transparent;
  border-radius: var(--r-sm); padding: var(--sp-2) var(--sp-2);
  color: var(--ink); font: inherit;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.t-input:hover { border-color: var(--line-2); }
.t-input:focus { outline: none; border-color: var(--acc); background: var(--surface); box-shadow: 0 0 0 3px var(--acc-soft); }
/* Las columnas numéricas se dimensionan al TEXTO (`td.num { width: 1% }`), así
   que un input con padding y borde queda más ancho que su celda y recorta la
   cifra: "11780" se veía "1178". El ancho mínimo en `ch` lo resuelve sin fijar
   píxeles, y el padding corto devuelve el espacio que el borde se llevó. */
.t-input.num {
  text-align: right; font-variant-numeric: tabular-nums;
  min-width: 10ch; padding-left: var(--sp-1); padding-right: var(--sp-1);
}
thead .t-input { color: var(--mut); font-weight: 600; }
thead .t-input:hover { border-color: var(--line-2); }
thead .t-input:focus { border-color: var(--acc); color: var(--ink); }

.row-del {
  background: none; border: 0; cursor: pointer; color: var(--bad);
  opacity: 0; font-size: 1rem; line-height: 1; padding: var(--sp-1);
  border-radius: var(--r-sm); transition: opacity var(--t-fast), background var(--t-fast);
}
tr:hover .row-del, .row-del:focus-visible { opacity: 1; }
.row-del:hover { background: var(--bad-bg); }

.add-line td { padding: var(--sp-2) var(--sp-4); }
.add-line button, .add-section {
  background: none; border: 0; color: var(--acc); cursor: pointer;
  font: inherit; font-weight: 600; font-size: .84rem; padding: var(--sp-2);
  border-radius: var(--r-sm); transition: background var(--t-fast);
}
.add-line button:hover { background: var(--acc-soft); }
.add-section {
  width: 100%; border: 1px dashed var(--line-2); padding: var(--sp-3);
  transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast);
}
.add-section:hover { border-color: var(--acc); background: var(--acc-soft); }

/* ---------- Tabla comparativa ---------- */
.comp { width: 100%; border-collapse: collapse; font-size: .88rem; }
.comp td { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line); }
.comp thead th:first-child, .comp td:first-child { text-align: left; }
.comp tbody tr:nth-child(even) td { background: var(--row-alt); }
.comp .ref { background: var(--ref); border-left: 1px solid var(--ref-line); border-right: 1px solid var(--ref-line); }
.comp td.best { background: var(--acc-soft); font-weight: 600; color: var(--ink); }

/* ---------- Barras ---------- */
.chart { display: grid; gap: var(--sp-3); }
.c-row { display: grid; grid-template-columns: 1fr 2fr auto; gap: var(--sp-3); align-items: center; }
.c-name { font-size: .84rem; color: var(--ink-2); }
.c-track { background: var(--chart-track); height: 8px; border-radius: 999px; overflow: hidden; }
.c-fill { background: var(--d1); height: 100%; border-radius: 999px; transition: width var(--t-slow); }
.c-row.lead .c-fill { background: var(--acc-fill); }
.c-val { font-size: .84rem; color: var(--mut); font-variant-numeric: tabular-nums; }
.c-row.lead .c-val { color: var(--ink); font-weight: 600; }

/* ---------- Badges ----------
   El fondo suave con texto de color es lo que hace que un estado se lea de un
   vistazo. El borde de Ácido dejaba todos los estados con el mismo peso. */
.badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  border-radius: 999px; padding: .15rem .55rem;
  font-size: .74rem; font-weight: 600; white-space: nowrap;
}
.b-ok { background: var(--ok-bg); color: var(--ok); }
.b-warn { background: var(--warn-bg); color: var(--warn); }
.b-bad { background: var(--bad-bg); color: var(--bad); }
.b-mut { background: var(--surface-3); color: var(--mut); }
[hidden] { display: none !important; }

/* ---------- Opciones y chips ---------- */
.nr-opcion {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--sp-3); cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.nr-opcion:hover { border-color: var(--line-2); background: var(--surface-2); }
.nr-opcion:has(input:checked) { border-color: var(--acc); background: var(--acc-soft); }
.nr-opcion input { margin-top: .2rem; }
.chk-inline { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: .88rem; }
.chk-inline input[type="checkbox"] { margin: 0; }

.pill {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: var(--acc-soft); color: var(--acc);
  border-radius: 999px; padding: .2rem .3rem .2rem .7rem;
  font-size: .8rem; font-weight: 600;
}
.pill .x {
  cursor: pointer; border: 0; background: none; color: inherit;
  border-radius: 999px; width: 18px; height: 18px; line-height: 1;
  display: inline-grid; place-items: center;
  transition: background var(--t-fast);
}
.pill .x:hover { background: color-mix(in srgb, var(--acc) 18%, transparent); }

/* ---------- Botones ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  height: var(--control-h); padding: 0 var(--sp-4);
  border: 1px solid var(--line-2); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: .84rem; font-weight: 600; cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast),
              color var(--t-fast), box-shadow var(--t-fast);
}
.btn:hover { background: var(--surface-2); border-color: var(--mut); }
.btn.pri { background: var(--acc-fill); border-color: var(--acc-fill); color: var(--acc-ink); }
.btn.pri:hover { filter: brightness(1.06); box-shadow: 0 2px 10px color-mix(in srgb, var(--acc-fill) 35%, transparent); }
.btn:disabled { background: var(--surface-2); border-color: var(--line); color: var(--mut); cursor: not-allowed; filter: none; box-shadow: none; }
.btn.danger { background: var(--surface); border-color: var(--bad); color: var(--bad); }
.btn.danger:hover { background: var(--bad-bg); }

/* ---------- Formularios ---------- */
.field { display: grid; gap: var(--sp-2); }
.field label { font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--mut); }
.field input, .field select, .field textarea {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-2); border-radius: var(--r-sm);
  padding: 0 var(--sp-3); min-height: var(--control-h);
  font: inherit; font-size: .9rem; width: 100%;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.field textarea { padding: var(--sp-3); min-height: 5rem; line-height: 1.5; }
.field input::placeholder, .field textarea::placeholder { color: var(--mut); }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--mut); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--acc); box-shadow: 0 0 0 3px var(--acc-soft);
}
.field .error-msg { font-size: .78rem; color: var(--bad); }
.field.invalid input, .field.invalid select, .field.invalid textarea { border-color: var(--bad); }
.field.invalid input:focus { box-shadow: 0 0 0 3px var(--bad-bg); }
input[type="checkbox"], input[type="radio"] { accent-color: var(--acc); width: 16px; height: 16px; }

/* ---------- Toasts ---------- */
.toast {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-left: 4px solid var(--mut);
  border-radius: var(--r-sm); box-shadow: var(--sh-2);
  padding: var(--sp-3) var(--sp-4); font-size: .88rem;
}
.toast.ok { border-left-color: var(--ok); }
.toast.warn { border-left-color: var(--warn); }
.toast.bad { border-left-color: var(--bad); }

/* ---------- Estados vacíos y esqueletos ---------- */
.empty {
  border: 1px dashed var(--line-2); border-radius: var(--r);
  padding: var(--sp-6) var(--sp-4); text-align: center; color: var(--mut);
  display: grid; gap: var(--sp-2); justify-items: center;
}
.empty strong { color: var(--ink); font-size: 1rem; font-weight: 600; }
.skeleton { background: var(--surface-3); border-radius: var(--r-sm); animation: sk-pulse 1.4s ease-in-out infinite; }
@keyframes sk-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

/* ---------- Barra de acciones ----------
   Era una banda de color; ahora es una superficie con sombra hacia arriba, que
   es lo que dice "esto flota sobre el contenido" sin gritarlo. */
.actionbar {
  position: sticky; bottom: 0; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface); color: var(--ink);
  border-top: 1px solid var(--line);
  box-shadow: 0 -6px 20px rgba(15, 23, 42, .06);
}
.actionbar .t { font-size: .88rem; color: var(--mut); }
.actionbar .pill { background: var(--acc-soft); color: var(--acc); }
.actionbar .btn { border-color: var(--line-2); background: var(--surface); color: var(--ink); }
.actionbar .btn:hover { background: var(--surface-2); }
.actionbar .btn.pri { background: var(--acc-fill); border-color: var(--acc-fill); color: var(--acc-ink); }
.actionbar .cta { margin-left: auto; display: flex; gap: var(--sp-2); }

/* ---------- Overlay y modal ---------- */
.overlay {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .45);
  backdrop-filter: blur(2px);
  display: none; place-items: center; z-index: var(--z-modal); padding: var(--sp-4);
}
.overlay.open { display: grid; }
.modal {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--sh-2); max-width: 560px; width: 100%;
  animation: modal-in var(--t-med);
}
@keyframes modal-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.modal > header {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4); border-bottom: 1px solid var(--line);
  font-weight: 600; font-size: 1rem;
}
.modal > header .close {
  margin-left: auto; background: none; border: 0; cursor: pointer;
  color: var(--mut); font-size: 1.2rem; line-height: 1;
  width: 28px; height: 28px; border-radius: var(--r-sm);
  transition: background var(--t-fast), color var(--t-fast);
}
.modal > header .close:hover { background: var(--surface-2); color: var(--ink); }

/* ---------- Pestañas ---------- */
.tabs { display: flex; gap: var(--sp-1); border-bottom: 1px solid var(--line); }
.tabs span, .tabs button {
  background: none; border: 0; cursor: pointer; font: inherit;
  font-size: .88rem; font-weight: 500; color: var(--mut);
  padding: var(--sp-3) var(--sp-3); border-bottom: 2px solid transparent;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.tabs span:hover, .tabs button:hover { color: var(--ink); }
.tabs .on { color: var(--acc); border-bottom-color: var(--acc); font-weight: 600; }

/* ---------- Entradas ---------- */
.fade-in { animation: fade-in var(--t-med); }
@keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ---------- Utilidades de layout (spec 30) ---------- */
.fila { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.fila-fin { justify-content: flex-end; }
.fila-entre { justify-content: space-between; }
.fila-centro { justify-content: center; }
.fila-1 { gap: var(--sp-1); }
.pila { display: grid; gap: var(--sp-3); }
.pila-1 { gap: var(--sp-1); }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: var(--sp-1); }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.ancho-corto { max-width: 22rem; }
.ancho-medio { max-width: 34rem; }
.tinta { color: var(--ink); }
.tinta-bad { color: var(--bad); }
.kv { font-size: .82rem; color: var(--mut); }
.clickable { cursor: pointer; }
.enlace-acc { color: var(--acc); }
.enlace-btn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--acc); font: inherit; font-weight: 600;
}
.enlace-btn:hover { text-decoration: underline; text-underline-offset: 3px; }
.mach-lista { display: grid; gap: var(--sp-2); }
tr.anulada > td { opacity: .55; text-decoration: line-through; }
tr.anulada > td .badge { text-decoration: none; }
.btn.btn-mini { height: 30px; padding: 0 var(--sp-3); font-size: .78rem; }
.skeleton-alto { height: 8rem; }
.skeleton-bajo { height: 2.4rem; }
.ficha-fila { display: flex; justify-content: space-between; gap: var(--sp-4); padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); }
.ficha-fila > .kv { flex: 0 0 auto; }
.ficha-total { font-weight: 700; color: var(--ink); border-bottom: 0; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .kpis { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 760px) {
  .page { padding: var(--sp-4); }
  .topbar nav { display: none; }
  .page-head h1, .page-head h2 { font-size: 1.35rem; }

  /* Tablas como tarjetas: cada fila se lee sola en un teléfono. */
  .table:not([data-notarjeta]) { display: block; }
  .table:not([data-notarjeta]) thead { display: none; }
  .table:not([data-notarjeta]) tbody tr {
    display: grid; gap: var(--sp-1);
    border: 1px solid var(--line); border-radius: var(--r);
    padding: var(--sp-3); margin-bottom: var(--sp-3); background: var(--surface);
  }
  .table:not([data-notarjeta]) tbody tr:hover { background: var(--surface-2); }
  .table:not([data-notarjeta]) td {
    display: flex; justify-content: space-between; gap: var(--sp-4);
    border: 0; padding: var(--sp-1) 0; text-align: right;
  }
  .table:not([data-notarjeta]) td::before {
    content: attr(data-etq); color: var(--mut); font-size: .74rem;
    font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
    text-align: left;
  }
  .table:not([data-notarjeta]) td[data-etq=""]::before { content: none; }
  .table:not([data-notarjeta]) tr.add-line { border-style: dashed; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

/* ---------- Calendario al costado de la lista (spec 73 §5) ----------
   Estas clases vivían al final de `acido.css` y se me pasaron en el inventario
   de la migración: sin ellas el calendario lateral pierde su rejilla y los
   días salen en una sola línea. Quedan dichas acá para que la próxima lectura
   del archivo las encuentre donde deben estar. */
.con-lateral { display: grid; grid-template-columns: 1fr 18rem; gap: var(--sp-4); align-items: start; }
.con-lateral.sin-lateral { grid-template-columns: 1fr; }
/* Bajo 1180px se pliega solo: la lista necesita el ancho más que el calendario. */
@media (max-width: 1180px) {
  .con-lateral { grid-template-columns: 1fr; }
  #cal-lateral { display: none; }
}

.cl-semana, .cl-rejilla { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cl-semana { text-align: center; }
.cl-dia {
  display: grid; gap: 0; justify-items: center; align-content: center;
  min-height: 2.2rem; padding: var(--sp-1) 0;
  background: none; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--ink-2); font: inherit; font-size: .78rem; cursor: default;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.cl-dia.cl-con { cursor: pointer; border-color: var(--line); }
.cl-dia.cl-con:hover { border-color: var(--acc); background: var(--acc-soft); color: var(--ink); }
.cl-dia.cl-vacio { visibility: hidden; }
.cl-dia.cl-hoy { background: var(--acc-soft); }
.cl-dia.cl-hoy .cl-n { font-weight: 700; color: var(--acc); }
/* Saturado: borde de aviso Y la marca de siempre — nunca solo color (spec 23). */
.cl-dia.cl-sat { border-color: var(--warn); }
/* Las marcas se dibujan con CSS, no con glifos (spec 32): un `●` no hereda el
   tema ni la geometría. La FORMA distingue evento de actividad además del
   color, que es lo que pide la spec 23 — el color acelera, no informa. */
.cl-marcas { display: flex; gap: 2px; align-items: center; min-height: .45rem; }
.cl-ev, .cl-act { display: inline-block; width: .34rem; height: .34rem; }
.cl-ev  { background: var(--d1); border-radius: 999px; }    /* punto = evento */
.cl-act {                                                   /* triángulo = actividad */
  width: 0; height: 0; background: none;
  border-left: .2rem solid transparent;
  border-right: .2rem solid transparent;
  border-bottom: .34rem solid var(--warn);
}

/* ---------- Utilidades que faltaban del inventario ---------- */
.fila-3 { gap: var(--sp-3); }
.fila-4 { gap: var(--sp-4); }
.pila-2 { gap: var(--sp-2); }
.pila-4 { gap: var(--sp-4); }
.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: var(--sp-1); }
.mb-2 { margin-bottom: var(--sp-2); }
.mb-3 { margin-bottom: var(--sp-3); }
.mb-4 { margin-bottom: var(--sp-4); }
tr.anulada > td .kv { text-decoration: none; }

/* En móvil, la tabla-tarjeta necesita estas tres reglas para no dejar bordes
   dobles ni etiquetas fantasma. */
@media (max-width: 760px) {
  .table:not([data-notarjeta]) tbody { display: block; }
  .table:not([data-notarjeta]) tr { display: block; }
  .table:not([data-notarjeta]) td:not([data-etq])::before { content: none; }
  .table:not([data-notarjeta]) tfoot tr,
  .table:not([data-notarjeta]) tr.total,
  .table:not([data-notarjeta]) tr.add-line { border-width: 0 0 1px 0; border-radius: 0; }
}

/* ---------- La puerta de entrada (spec 08 §1) ----------
   Pantalla partida: el argumento a la izquierda, el formulario a la derecha. La
   usan las CUATRO puertas —la app, la consola, «olvidé mi contraseña» y «elige
   tu contraseña»— porque puertas distintas al mismo producto se leen como
   productos distintos.

   El panel izquierdo va sobre `--bg`, el mismo lienzo del resto de la app, y no
   sobre un degradado a sangre: media pantalla de color saturado es exactamente
   lo que el sistema dice que NO hace (spec 20 — la jerarquía se construye con
   superficie y espacio antes que con color). La puerta tiene que verse como la
   herramienta que abre, no como su anuncio.

   Es la única pantalla del sistema donde el acento no es el del tenant: nadie
   se ha identificado todavía, así que no hay tenant del que sacarlo. */
/* 56/44 y no 50/50: una división simétrica se lee como dos pantallas pegadas.
   La asimetría le da un lado dominante y otro de trabajo. */
.auth { display: grid; grid-template-columns: 61% 1fr; min-height: 100vh; }
/* `dvh` en cuanto el navegador lo entienda: en un teléfono `100vh` cuenta la
   barra que se esconde al hacer scroll y NO encoge con el teclado abierto, así
   que el botón «Entrar» se va debajo del teclado justo cuando hace falta. */
@supports (min-height: 100dvh) { .auth { min-height: 100dvh; } }
/* El panel va PRIMERO a la vista y SEGUNDO en el DOM (spec 23): así el lector
   de pantalla y el tabulador llegan al formulario sin atravesar el argumento de
   venta, y el `h1` del formulario precede al `h2` del panel en vez de al revés.
   Lo visual lo repone `order`; el orden del documento es el que importa. */
.auth-marca { order: -1; }

.auth-marca {
  position: relative; overflow: hidden;
  padding: var(--sp-8) clamp(var(--sp-5), 5vw, var(--sp-8));
  background: var(--marca-bg); color: var(--marca-ink);
  display: grid; grid-template-columns: minmax(0, 560px);
  align-content: center; justify-content: center; gap: var(--sp-5);
  /* Adentro de este panel el sistema es oscuro pase lo que pase. Se remapean
     los tokens en vez de pintar colores sueltos: así el objeto 3D, los tics y
     cualquier cosa que se agregue mañana salen bien sin saber dónde están. */
  --surface: var(--marca-surface);
  --surface-2: var(--marca-surface-2);
  --surface-3: var(--marca-surface-3);
  --ink: var(--marca-ink);
  --ink-2: var(--marca-ink);
  --mut: var(--marca-mut);
  --line: var(--marca-line);
  --line-2: var(--marca-line);
  --chart-track: rgba(255, 255, 255, .10);
  --vol-tapa: rgba(255, 255, 255, .07);
  --vol-frente: rgba(0, 0, 0, .26);
  --vol-lado: rgba(0, 0, 0, .46);
  --vol-piso: rgba(0, 0, 0, .55);
  --acc: var(--marca-acc);
}
/* Resplandor y trama: los dos muy tenues. Es lo que evita que medio lienzo de
   color plano se vea como una cartulina. */
.auth-marca::before {
  content: ""; position: absolute; inset: -24px; pointer-events: none;
  background:
    radial-gradient(60% 45% at 82% 6%, var(--marca-bg-2), transparent 70%),
    radial-gradient(rgba(255, 255, 255, .10) 1px, transparent 1px);
  background-size: auto, 26px 26px;
  /* Paralaje del fondo: la trama se corre al doble que el resplandor, así el
     panel tiene dos planos y no uno. Rango cortísimo —±10px— porque esto se
     tiene que sentir, no ver. `inset: -24px` evita que asome el borde. */
  transform: translate3d(calc(var(--px, 0) * 10px), calc(var(--py, 0) * 10px), 0);
  transition: transform 600ms cubic-bezier(.22, .61, .36, 1);
}
.auth-marca > * { position: relative; }
/* La secuencia de entrada (spec 08 §1). Es lo que hace distinta a esta puerta
   de la referencia, que es una imagen fija: acá la pantalla se ARMA una vez,
   en un orden que se lee —quién soy, qué hago, con qué, y las pruebas—, y
   termina completamente quieta. No hay nada que se repita ni que espere. */
@keyframes auth-entra {
  from { opacity: 0; transform: translateY(14px); }
}
.auth-marca > * {
  animation: auth-entra 640ms cubic-bezier(.22, .61, .36, 1) both;
}
.auth-marca > *:nth-child(1) { animation-delay: 60ms; }
.auth-marca > *:nth-child(2) { animation-delay: 170ms; }
.auth-marca > *:nth-child(3) { animation-delay: 260ms; }
.auth-marca > *:nth-child(4) { animation-delay: 340ms; }
.auth-marca > *:nth-child(5) { animation-delay: 430ms; }

.auth-logo {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: 1.02rem; font-weight: 700; letter-spacing: -.02em;
}
.auth-logo .marca-ico {
  width: 34px; height: 34px; border-radius: var(--r-sm);
  display: grid; place-items: center;
  background: var(--acc-fill); color: var(--acc-ink);
}
.auth-logo img { height: 28px; display: block; }
.auth-tit {
  margin: 0; max-width: 22ch;
  font-size: clamp(1.9rem, 3.3vw, 3.05rem); font-weight: 700;
  letter-spacing: -.035em; line-height: 1.1; text-wrap: balance;
}
/* El segundo renglón en el acento. Sobre el panel oscuro el acento de texto
   (`--acc`) es el que tiene contraste; `--acc-fill` es para rellenos. */
.auth-tit em { font-style: normal; color: var(--acc); }
.auth-sub { margin: 0; max-width: 46ch; font-size: 1.02rem; color: var(--marca-mut); }

/* --- El gráfico: cinco prismas sobre un zócalo ---------------------------
   Extrusión REAL: cada barra son tres caras (tapa, frente, lado) colocadas en
   el espacio, no una sombra apilada que la finge. Importa porque la sombra
   apilada se delata en cuanto el objeto gira —el falso canto no cambia de
   ángulo— y acá el objeto gira con el puntero.

   La luz viene siempre del mismo lado: tapa iluminada, frente a media sombra,
   lado en la más oscura, con los velos `--vol-*`. Un solo mecanismo para las
   barras neutras y para la del acento, y para los dos temas.

   El movimiento está permitido solo en esta pantalla (spec 20 §6 lo prohíbe en
   el resto) y con el rango corto: ±4° sobre una inclinación de base. */
.auth-escena {
  perspective: 1250px; perspective-origin: 50% 44%;
  padding: var(--sp-4) 0;
  pointer-events: none;   /* nadie pierde un clic contra la escena */
  position: relative;     /* ancla de la sombra de contacto */
}
.auth-grafico {
  --obj-w: 320px;
  position: relative; width: var(--obj-w); height: 224px; margin: 0 auto;
  transform-style: preserve-3d;
  /* Vista de tres cuartos. Sin inclinación de base el objeto se ve de frente y
     no se distingue de cinco rectángulos planos: el volumen es el argumento. */
  /* 26° de cabeceo, no 15: con el ángulo rasante las tapas se ven de canto, el
     objeto pierde la cara iluminada y la retícula del zócalo se comprime hasta
     desaparecer. Mirar un poco desde arriba es lo que lo vuelve un sólido. */
  transform: rotateX(calc(26deg + var(--rx, 0deg))) rotateY(calc(-24deg + var(--ry, 0deg)));
  transition: transform 420ms cubic-bezier(.22, .61, .36, 1);
}

/* Una pieza = un prisma. `--h` su altura, `--d` su fondo, `--n` su lugar. */
.auth-grafico .pieza {
  position: absolute; bottom: 0; transform-style: preserve-3d;
  height: var(--h); width: var(--ancho, 45px);
  left: calc(var(--n) * (var(--ancho, 45px) + 24px));
}
.auth-grafico .pieza > i {
  position: absolute; display: block;
  /* El color de base y el velo, en capas: así la cara con acento y la neutra
     se sombrean con la MISMA regla. */
  background-color: var(--vol-base, var(--surface));
  background-image: linear-gradient(var(--vel), var(--vel));
  border: 1px solid var(--line);
}
.auth-grafico .pieza .frente { inset: 0; transform: translateZ(calc(var(--d) / 2)); --vel: var(--vol-frente); }
.auth-grafico .pieza .lado {
  top: 0; bottom: 0; width: var(--d); left: calc(100% - var(--d) / 2);
  transform: rotateY(90deg); --vel: var(--vol-lado);
}
.auth-grafico .pieza .tapa {
  left: 0; right: 0; height: var(--d); top: calc(var(--d) / -2);
  transform: rotateX(90deg); --vel: var(--vol-tapa);
}
/* La barra líder va en el relleno del acento: es el «dato líder» que el sistema
   ya reserva para `.chart .lead` (spec 20 §5). Una sola, nunca dos. */
.auth-grafico .pieza.lider > i { --vol-base: var(--acc-fill); border-color: var(--acc-fill); }

/* Una pieza HUECA: mismo prisma, sin relleno. Es lo que salva al objeto de ser
   el gráfico de barras de cualquier dashboard — un volumen sólido y otro que
   todavía no lo es, que es exactamente cómo se ve un mes a medias en un ERP:
   lo cerrado y lo que falta cerrar. Sin escribir una palabra. */
.auth-grafico .pieza.hueca > i {
  background-color: transparent; background-image: none;
  border: 1px dashed var(--line-2);
}

/* El zócalo: las barras se paran en algo. Sin él quedan flotando, que es el
   detalle que separa un objeto de un montón de rectángulos. Tiene más fondo
   que las barras, así que ellas quedan embutidas y no al borde. */
.auth-grafico .zocalo {
  /* Voladizo corto (12px por lado, no 20) y menos fondo: con el zócalo largo, la
     perspectiva lo convierte en una cuña blanca que sobresale y se lleva la
     mirada. Y va en `--surface-2`, un punto por debajo de las barras: es la base,
     no el protagonista — en `--surface` la tapa quedaba en blanco puro y brillaba
     más que las piezas que sostiene. */
  --h: 9px; --d: 34px;
  left: -9px; bottom: -9px; width: calc(var(--obj-w) + 18px);
}
/* Tres correcciones sobre el mismo problema: el zócalo se estaba llevando la
   mirada. (1) Va en `--surface-2`, un punto por debajo de las barras. (2) Su
   tapa lleva el velo del FRENTE y no el de la tapa: sin eso, la cara iluminada
   de la base queda más clara que la cara frontal de las piezas y la base brilla
   más que lo que sostiene. (3) Apenas 4px más de fondo que las barras, para que
   no quede un andén vacío por delante. */
.auth-grafico .zocalo > i { --vol-base: var(--surface-2); }
.auth-grafico .zocalo .tapa { --vel: var(--vol-frente); }
/* La sombra de contacto: sin ella el objeto flota sobre el lienzo, y flotar es
   lo que hace que algo se vea pegado encima en vez de estar ahí.

   Va FUERA del espacio 3D, hermana del objeto y no hija: metida adentro, la
   rotación del contenedor se le suma a su propio `rotateX(90deg)` y termina
   mirando para otro lado —o detrás del zócalo—. Un suelo tampoco tiene por qué
   girar con la pieza que lo pisa. */
.auth-piso {
  /* Centrada como el objeto: si una va centrada y la otra clavada a un borde,
     la sombra queda corrida y se nota más que si no estuviera. */
  position: absolute; left: 50%; margin-left: -150px; bottom: 6px;
  width: 300px; height: 34px;
  background: radial-gradient(closest-side ellipse, var(--vol-piso), transparent 76%);
  filter: blur(10px); pointer-events: none;
}

/* Entrada: las barras CRECEN desde el zócalo, escalonadas. Es el gesto que hace
   un gráfico al cargar; acá no es adorno, es el objeto poniéndose de pie. */
@keyframes auth-crece { from { height: 0; } }
.auth-grafico .pieza { animation: auth-crece 720ms cubic-bezier(.22, .61, .36, 1) both;
                       animation-delay: calc(520ms + var(--n) * 90ms); }
.auth-grafico .zocalo { animation-duration: 380ms; animation-delay: 400ms; }

.auth-lista { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.auth-lista li { display: flex; align-items: center; gap: var(--sp-3); font-size: .94rem; font-weight: 600; color: var(--marca-ink); }
.auth-lista .tic {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: var(--r-sm);
  display: grid; place-items: center;
  background: var(--acc-fill); color: var(--acc-ink);
}

/* La columna del formulario es el LIENZO, y el formulario una tarjeta encima.
   Antes los dos eran `--surface`: en tema claro el formulario quedaba suelto
   sobre un fondo del mismo tono, y en oscuro los dos lados de la pantalla eran
   casi del mismo color y la división se perdía. Esto es literalmente lo que el
   sistema dice de sí mismo (spec 20): tarjetas apenas elevadas sobre el lienzo. */
.auth-forma {
  position: relative; z-index: 1;   /* la tarjeta pisa el panel, no al revés */
  /* `justify-items: start` y no `center`: para que el montaje sobre la división
     sea una medida FIJA y no lo que sobre de centrar en una columna que cambia
     de ancho con la ventana. */
  display: grid; align-items: center; justify-items: start;
  padding: var(--sp-6) var(--sp-5);
  background: var(--bg);
}
.auth-tema { position: absolute; top: var(--sp-4); right: var(--sp-4); }
/* La tarjeta MONTA sobre la división: se corre a la izquierda y pisa el borde
   del panel oscuro. Es lo que convierte dos mitades pegadas en una sola
   composición, y no cuesta un solo color nuevo — es superficie y espacio, que
   es con lo que este sistema construye jerarquía (spec 20).

   Al pisar una superficie oscura necesita la sombra de modal (`--sh-2`): con la
   de tarjeta se pierde contra el panel y el montaje se lee como un error de
   alineación en vez de como una decisión. Por lo mismo el montaje es de 112px y
   no de 40: un solape tímido parece un desalineado. */
.auth-caja {
  position: relative; z-index: 2;
  margin-left: calc((var(--sp-5) + 112px) * -1);  /* 112px encima del panel */
  width: min(420px, 100%); display: grid; gap: var(--sp-4);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--sh-2);
  padding: var(--sp-6);
}
.auth-caja h1 { margin: 0; font-size: 1.6rem; font-weight: var(--h-weight); letter-spacing: -.025em; }
.auth-caja h1::after { content: none; }
.auth-caja .auth-saludo { margin: calc(var(--sp-2) * -1) 0 0; color: var(--mut); font-size: .92rem; }
.auth-caja form { display: grid; gap: var(--sp-4); }
/* La etiqueta y su enlace de ayuda en la misma línea: es donde alguien busca
   «olvidé mi contraseña», justo cuando descubre que no la recuerda. */
.auth-etq { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.auth-etq label { margin: 0; }
.auth-etq a, .auth-etq button {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: .78rem; font-weight: 600; color: var(--acc);
}
/* Campo con ícono adentro: el ícono no es adorno, distingue de un vistazo el
   correo de la contraseña cuando los dos son cajas iguales. */
.campo-ico { position: relative; display: block; }
.campo-ico > svg {
  position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px;   /* fijo acá también: un SVG sin medidas crece
                                  hasta llenar su contenedor y tapa el campo */
  color: var(--mut); pointer-events: none;
}
.campo-ico input { padding-left: calc(var(--sp-3) * 2 + 18px); }
.campo-ico input[type="password"], .campo-ico input.con-ojo { padding-right: calc(var(--sp-3) * 2 + 18px); }
.campo-ico .ojo {
  position: absolute; right: var(--sp-2); top: 50%; transform: translateY(-50%);
  background: none; border: 0; cursor: pointer; color: var(--mut);
  width: 30px; height: 30px; border-radius: var(--r-sm);
  display: grid; place-items: center;
  transition: color var(--t-fast), background var(--t-fast);
}
.campo-ico .ojo:hover { color: var(--ink); background: var(--surface-2); }
.auth-caja .btn.pri {
  width: 100%; height: 44px; font-size: .92rem;
  /* En flex, la flecha se alinea sola con el texto: apoyarse en el
     `vertical-align` del SVG la deja alta o baja según la fuente. */
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
}
.auth-caja .auth-abajo { text-align: center; font-size: .88rem; color: var(--mut);
  margin: var(--sp-1) 0 0; padding-top: var(--sp-4); border-top: 1px solid var(--line); }
/* Aviso de Bloq Mayús: va en el color de atención, no en el de error — no es
   un fallo todavía, es lo que lo evita. */
.aviso-mayus { display: block; margin-top: var(--sp-2); color: var(--warn); font-weight: 600; }
/* Pie de la columna del formulario: la cierra por abajo en vez de dejar el
   formulario flotando en medio de la nada. Anclado al fondo, no al flujo — si
   fuera parte de la caja, empujaría el formulario fuera del centro óptico. */
/* Marca compacta para el teléfono: ahí el panel desaparece, y un formulario sin
   logotipo no dice a qué estás entrando. Oculta en escritorio, donde el panel ya
   lo muestra — dos veces la misma marca es peor que una. */
.auth-marca-min { display: none; }

.auth-forma > .auth-copy {
  position: absolute; left: 0; right: 0; bottom: var(--sp-5);
  margin: 0; text-align: center; font-size: .78rem; color: var(--mut);
}
.auth-caja .auth-copy { text-align: center; font-size: .78rem; color: var(--mut); }

/* --- Al entrar, la puerta se ABRE -------------------------------------------
   Las dos mitades se apartan y dejan ver la aplicación, que ya está pintada
   detrás. Por eso no cuesta espera: el `enrutar()` ocurre debajo mientras la
   puerta se corre encima, y lo único que se agrega es la animación.

   Es lo que hace distinta a esta puerta de la referencia, que corta a negro y
   recarga. También es el único lugar del sistema donde algo se desplaza de
   verdad (spec 20 §6 lo prohíbe en el resto): acá el desplazamiento ES el
   mensaje — entraste. */
.auth.abriendo {
  position: fixed; inset: 0; z-index: var(--z-pantalla);
  pointer-events: none;   /* la app de abajo ya es clickeable */
}
.auth.abriendo .auth-marca,
.auth.abriendo .auth-forma {
  transition: transform 520ms cubic-bezier(.6, 0, .3, 1);
}
.auth.abriendo .auth-marca { transform: translateX(-102%); }
.auth.abriendo .auth-forma { transform: translateX(102%); }

/* Alturas cortas: el panel recorta lo que no cabe (`overflow: hidden`), y un
   titular partido a la mitad se lee como un defecto, no como un diseño. Se
   compacta primero el aire y, si aun así no entra, el objeto cede su lugar —
   el texto es lo que explica el producto; el objeto solo lo acompaña. */
@media (max-height: 900px) {
  .auth-marca { gap: var(--sp-4); padding-top: var(--sp-6); padding-bottom: var(--sp-6); }
  .auth-escena { padding: 0; }
}
@media (max-height: 780px) {
  .auth-escena { display: none; }
}

/* En un teléfono lo único que importa es el formulario: el panel de marca no se
   apila debajo —nadie hace scroll para leer un argumento de venta cuando lo que
   quiere es entrar—, desaparece. */
@media (max-width: 900px) {
  /* En el teléfono el panel NO desaparece: se convierte en una banda de arriba
     con el logotipo y el objeto. Lo que se va es el argumento de venta —eso sí
     que nadie lo lee para entrar—, pero la marca y la gráfica se quedan: son lo
     que hace que la pantalla chica siga siendo de este producto y no un
     formulario cualquiera. */
  .auth { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .auth { position: relative; }
  .auth-marca {
    display: grid; grid-template-columns: 1fr;
    /* `start` y no `center`: la banda se dimensiona por su contenido, así que
       visualmente da igual — pero si alguna vez el alto le queda corto (un
       teléfono en horizontal), `center` desborda por ARRIBA y el `overflow:
       hidden` decapita el logotipo. `start` solo puede desbordar hacia abajo. */
    justify-items: center; align-content: start;
    gap: var(--sp-3);
    /* Relleno inferior generoso: el objeto está en perspectiva y su base se
       proyecta MÁS ABAJO que su caja. Con el `overflow: hidden` de la banda,
       ajustar al alto de la caja le corta el zócalo. */
    padding: var(--sp-5) var(--sp-4) var(--sp-6);
  }
  .auth-tit, .auth-sub, .auth-lista { display: none; }
  /* La banda ya trae el logotipo: la cabecera compacta sobra y sería la marca
     dos veces. */
  .auth-marca-min { display: none; }
  /* El rectángulo del objeto es su PROYECCIÓN, no su caja: girado mide más
     alto de lo que declara. Este aire de abajo es para eso. */
  .auth-escena { padding: var(--sp-2) 0 var(--sp-4); }
  /* El objeto encoge de verdad —ancho y barras—, no con `scale`: escalar deja
     la caja del tamaño viejo y abre un hueco debajo. */
  .auth-grafico { --obj-w: 250px; height: 190px; }
  .auth-grafico .pieza { --ancho: 34px; }
  .auth-grafico .pieza:not(.zocalo) { left: calc(var(--n) * (34px + 20px)); }
  /* Sin panel no hay división que pisar: la tarjeta vuelve al centro, y la
     columna deja de estar centrada verticalmente: se apila desde arriba, que es
     como se lee un teléfono y lo que deja sitio al teclado. */
  .auth-forma {
    /* Centrado también en el teléfono: apilar desde arriba dejaba un hueco
       grande abajo en una pantalla alta. Con el teclado abierto no estorba,
       porque `dvh` encoge el alto y, si no cabe, la página simplemente rueda. */
    justify-items: center; align-content: center;
    gap: var(--sp-5); padding: var(--sp-8) var(--sp-4) var(--sp-6);
  }
  .auth-caja { margin-left: 0; padding: var(--sp-5); box-shadow: var(--sh-1); }
  /* La marca, arriba del formulario. */
  .auth-marca-min { display: block; }
  .auth-marca-min .marca-ico { background: var(--acc-fill); color: var(--acc-ink); }
  /* El pie deja de ir anclado al fondo: con el teclado abierto se montaba
     encima del formulario. En el flujo, simplemente queda al final. */
  .auth-forma > .auth-copy { position: static; margin-top: var(--sp-2); }
  /* El botón de tema sube a la banda oscura, arriba a la derecha. Colgado de la
     columna del formulario caía justo encima de la tarjeta; anclado a `.auth`
     queda sobre la banda, que es espacio libre. */
  .auth-forma { position: static; }
  /* Alineado con el logotipo, no 20px más abajo: los dos arrancan en el mismo
     relleno superior de la banda. Y deja de ser una píldora blanca con texto
     —que sobre la banda oscura competía con la marca— para ser un control
     fantasma del MISMO alto que el logotipo: 34px, solo el ícono. */
  .auth-tema { top: var(--sp-5); right: var(--sp-4); }
  .auth-tema .tema-btn {
    width: 34px; height: 34px; padding: 0;
    display: grid; place-items: center;
    background: transparent; border-color: var(--marca-line); color: var(--marca-ink);
  }
  .auth-tema .tema-btn:hover { background: var(--marca-line); color: var(--marca-ink); }
  .auth-tema .tema-txt { display: none; }
  /* El logotipo a la izquierda y no centrado: centrado choca con el botón
     de tema en cuanto la pantalla baja de ~430px. El objeto sí va al
     centro, que es donde tiene que estar. */
  .auth-logo { justify-self: start; padding-right: 5.5rem; }
}

/* La escena de la puerta con `prefers-reduced-motion` (spec 23). */
@media (prefers-reduced-motion: reduce) {
  /* Se apaga el MOVIMIENTO, no el objeto: la inclinación de base se queda (sale
     de `--rx`/`--ry` en 0, que es el reposo) y lo que se va es la transición y
     la entrada. Un `transform: none` acá dejaría una pila plana y vacía, que es
     peor que no tenerla. */
  .auth-grafico { transition: none; }
  .auth-grafico .pieza { animation: none; }
  .auth-marca > * { animation: none; }
  .auth-marca::before { transition: none; transform: none; }
  /* La puerta no se abre: desaparece. A quien pide menos movimiento no se le
     entrega el mismo gesto más lento, se le entrega sin gesto. */
  .auth.abriendo .auth-marca, .auth.abriendo .auth-forma { transition: none; }
}
