/* ============================================================================
   VEKSAI · Área de clientes — hoja única del hub (clientes.veksai.com)

   La piel es la de la marca VEKSAI, heredada tal cual de
   public_html/herramientas/index.html y public_html/assets/nav.css:
   negro #0a0a0a, hueso #f0ede8, verde #b5ff6d, Syne para display y DM Sans
   para texto. Ningún color se escribe a pelo fuera de los bloques de tokens.

   DOS TEMAS, UN SISTEMA. Es la MISMA hoja con otra piel: no hay una sola regla
   de maquetación que dependa del tema, y no hay ni un elemento que exista en
   uno y no en el otro. Cambiar de tema es cambiar el bloque de variables.

   VEKSAI es una marca oscura, así que el OSCURO es el por defecto y el claro
   es una elección. Quién manda, por orden:

     1. lo que el cliente eligió aquí antes (localStorage 'veksai-theme'),
        que el guion incrustado del <head> traduce a [data-theme] antes del
        primer pintado;
     2. si no ha elegido nunca y no hay JavaScript, `prefers-color-scheme`;
     3. si el navegador no dice nada, oscuro.

   El bloque `@media (prefers-color-scheme: light)` NO es decorativo: es el
   único camino al claro cuando no hay JavaScript. Por eso el <html> ya NO
   viene con `data-theme="dark"` escrito en el marcado — con el atributo
   puesto a mano la media query no podía dispararse nunca.

   ATENCIÓN al vocabulario, que es el heredado de la marca y despista: --black
   es SIEMPRE el fondo de la página y --white SIEMPRE la tinta. En claro eso
   significa que --black vale papel (#f7f6f1) y --white vale casi negro. Es el
   mismo criterio que usa assets/nav.css de la web pública.

   EL ACENTO EN CLARO. El lima #b5ff6d sobre papel da 1,11:1: no vale ni para
   texto ni para una línea. Se parte en dos tokens:
     --accent   el acento TINTA (texto, enlaces, filetes, puntos, el precio y
                LAS BARRAS de estadísticas). En claro es #4f6a17, el mismo
                verde llevado a oliva: 5,70:1 sobre papel y 5,26:1 sobre --grey.
     --relleno  el acento MACIZO (fondo de botón y de pestaña activa). Ahí el
                lima sobrevive en los dos temas, porque el texto que lleva
                encima es tinta oscura: 15,13:1 en claro. Como el lima no se
                distingue del papel (1,11:1), en claro el relleno lleva
                --relleno-borde de acento tinta para que el botón tenga
                frontera: 5,70:1 contra la página.

   Todos los ratios de esta hoja están medidos con composición alfa sobre el
   fondo REAL de cada elemento, no entre tokens sueltos, y en los dos temas por
   separado (las dos trampas de CALIDAD.md). Mínimos: 4,5:1 texto, 3:1 texto
   grande, bordes de control y objetos gráficos.

   Reglas que se han seguido a propósito (CALIDAD.md / ANTIPATRONES_PLANTILLA.md):
   - jerarquía por espacio y tamaño, no por cajas: los módulos son filas
     editoriales separadas por filete, no una rejilla de tarjetas clónicas;
   - ritmo deliberado: el módulo NO activado ocupa más alto y lleva la cifra
     grande; el activo es una fila serena. La diferencia la marca el contenido;
   - radios cortos (2-4 px) y filete de 1 px en vez de sombras de kit de UI;
   - foco visible siempre, zona de toque de 44 px, y nada informado solo por color;
   - el fondo claro es PAPEL CÁLIDO (#f7f6f1), no el gris frío de SaaS que
     ANTIPATRONES_PLANTILLA.md señala como delator de plantilla.
   ========================================================================== */

:root {
  /* -------------------------------------------------- OSCURO (por defecto) */
  color-scheme: dark;

  --black: #0a0a0a;              /* fondo de página */
  --grey: #111;                  /* superficie elevada: campos, paneles, pistas */
  --mid: #191919;
  --white: #f0ede8;              /* tinta */

  --accent: #b5ff6d;             /* acento TINTA — 16,49:1 sobre --black */
  --accent-dim: rgba(181, 255, 109, 0.08);
  --border: rgba(181, 255, 109, 0.12);   /* filete decorativo del panel de Clara */

  /* Relleno macizo del botón de acción. En oscuro el lima ya se recorta solo
     contra la página (16,49:1), así que el borde es el propio lima. */
  --relleno: #b5ff6d;
  --relleno-tinta: #0a0a0a;      /* 16,49:1 sobre el relleno */
  --relleno-borde: #b5ff6d;
  --relleno-h: #f0ede8;
  --relleno-h-tinta: #0a0a0a;    /* 16,95:1 */

  --line: rgba(240, 237, 232, 0.13);     /* separador decorativo */
  --line-fuerte: rgba(240, 237, 232, 0.26);
  /* Frontera de CONTROL (botón, campo, casilla): 1.4.11 pide 3:1 y
     --line-fuerte se quedaba en 2,07:1. .40 da 3,39:1 sobre --black. */
  --borde-control: rgba(240, 237, 232, 0.40);

  --muted: #8e8e8a;              /* 6,02:1 sobre --black · 5,74:1 sobre --grey */
  --soft: rgba(240, 237, 232, 0.74);     /* 9,36:1 sobre --black */
  --warn: #f2c14e;               /* 11,80:1 — marca DEMO y bajadas de posición */
  --bad: #ff6b6b;                /* 7,13:1 */
  --bad-borde: rgba(255, 107, 107, 0.62);  /* 3,30:1 — frontera del botón de baja */
  --bad-fondo: rgba(255, 107, 107, 0.07);

  --font-display: 'Syne', system-ui, sans-serif;
  --font-body: 'DM Sans', system-ui, sans-serif;

  /* Escala de espacio: más de un valor, a propósito. */
  --e1: 8px;
  --e2: 14px;
  --e3: 22px;
  --e4: 34px;
  --e5: 52px;
  --e6: 84px;

  --rail: 268px;
}

/* ------------------------------------------------------------------ CLARO */
/* Se declara DESPUÉS de :root para ganarle el empate de especificidad cuando
   el cliente elige claro teniendo el sistema en oscuro. */
[data-theme="light"] {
  color-scheme: light;

  --black: #f7f6f1;              /* papel cálido, NO gris SaaS */
  --grey: #eeebe2;
  --mid: #e6e2d6;
  --white: #16160f;              /* tinta — 16,79:1 sobre papel */

  --accent: #4f6a17;             /* 5,70:1 sobre papel · 5,26:1 sobre --grey */
  --accent-dim: rgba(79, 106, 23, 0.10);
  --border: rgba(79, 106, 23, 0.36);

  --relleno: #b5ff6d;            /* el lima sobrevive: lleva tinta encima */
  --relleno-tinta: #16160f;      /* 15,13:1 sobre el lima */
  --relleno-borde: #4f6a17;      /* 5,70:1 contra el papel: le da frontera */
  --relleno-h: #4f6a17;
  --relleno-h-tinta: #f7f6f1;    /* 5,70:1 */

  --line: rgba(22, 22, 15, 0.14);
  --line-fuerte: rgba(22, 22, 15, 0.30);
  --borde-control: rgba(22, 22, 15, 0.52);  /* 3,59:1 sobre papel */

  --muted: #5c5c52;              /* 6,24:1 sobre papel · 5,67:1 sobre --grey */
  --soft: rgba(22, 22, 15, 0.76);        /* 8,02:1 sobre papel */
  --warn: #7d5200;               /* 6,30:1 — el ámbar llevado a tierra */
  --bad: #a4231c;                /* 6,84:1 */
  --bad-borde: rgba(164, 35, 28, 0.66);  /* 3,51:1 */
  --bad-fondo: rgba(164, 35, 28, 0.07);
}

/* Sin JavaScript no hay conmutador y no hay atributo: manda el sistema.
   `:not([data-theme="dark"])` es lo que impide que esto pise una elección
   explícita de oscuro hecha por alguien cuyo sistema está en claro. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --black: #f7f6f1;
    --grey: #eeebe2;
    --mid: #e6e2d6;
    --white: #16160f;

    --accent: #4f6a17;
    --accent-dim: rgba(79, 106, 23, 0.10);
    --border: rgba(79, 106, 23, 0.36);

    --relleno: #b5ff6d;
    --relleno-tinta: #16160f;
    --relleno-borde: #4f6a17;
    --relleno-h: #4f6a17;
    --relleno-h-tinta: #f7f6f1;

    --line: rgba(22, 22, 15, 0.14);
    --line-fuerte: rgba(22, 22, 15, 0.30);
    --borde-control: rgba(22, 22, 15, 0.52);

    --muted: #5c5c52;
    --soft: rgba(22, 22, 15, 0.76);
    --warn: #7d5200;
    --bad: #a4231c;
    --bad-borde: rgba(164, 35, 28, 0.66);
    --bad-fondo: rgba(164, 35, 28, 0.07);
  }
}

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

body {
  background: var(--black);
  color: var(--white);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 700; line-height: 1.12; letter-spacing: -0.015em; }

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

img, svg { max-width: 100%; height: auto; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
.btn--acento:focus-visible { outline-color: var(--white); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.saltar {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--accent); color: var(--black); padding: 12px 18px;
  font-weight: 700; text-decoration: none;
}
.saltar:focus { left: 8px; top: 8px; }

/* ------------------------------------------------ conmutador de tema ----- */
/* Un interruptor de verdad, no un botón que cambia de nombre: `role="switch"`
   con el nombre FIJO («Modo oscuro») y el estado en `aria-checked`. La etiqueta
   se pinta desde `data-etiqueta` para que lo que lee el lector de pantalla y lo
   que se ve sean literalmente la misma cadena.
   Es el mismo patrón que el de bravoadvocats.com (css/tema.css), retokenizado.

   Va INYECTADO por hub.js dentro de `.tema-anclaje`, no escrito en el marcado:
   sin JavaScript el interruptor no puede funcionar, y un control muerto es peor
   que ninguno. Sin JS manda `prefers-color-scheme`, que es cosa del CSS.

   La bola se mueve con `aria-checked`, no con `[data-theme]`: así el estado
   visible y el que anuncia el lector no pueden desincronizarse nunca. */

.tema-anclaje:empty { display: none; }

.tema-btn {
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 0;
  border: 0; background: transparent; cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 500;
  letter-spacing: 0.04em; color: var(--muted);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: color .18s ease;
}
.tema-btn::before { content: attr(data-etiqueta); white-space: nowrap; }
.tema-btn:hover, .tema-btn:focus-visible { color: var(--white); }

/* La pista: 44×24, con sol y luna como topes fijos siempre visibles. Los dos
   iconos están en los dos temas: lo que informa es dónde está la bola. */
.tema-track {
  position: relative; flex: none;
  width: 44px; height: 24px; border-radius: 999px;
  background: var(--grey);
  border: 1px solid var(--borde-control);
  transition: border-color .18s ease;
}
.tema-btn:hover .tema-track,
.tema-btn:focus-visible .tema-track { border-color: var(--white); }

.tema-btn__sol, .tema-btn__luna {
  position: absolute; top: 50%;
  width: 12px; height: 12px;
  transform: translateY(-50%);
  color: var(--muted); pointer-events: none;
}
.tema-btn__sol { left: 5px; }
.tema-btn__luna { right: 5px; }

/* La bola: `::after` sobre la pista, no un elemento más en el marcado. Oscuro
   es el modo de la casa, así que de serie está a la derecha, sobre la luna. */
.tema-track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent);
  transform: translateX(20px);
  transition: transform .25s cubic-bezier(.4, 0, .2, 1);
}
.tema-btn[aria-checked="false"] .tema-track::after { transform: translateX(0); }

/* ---------------------------------------------------------------- botones */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 11px 22px;
  font-family: var(--font-display); font-size: 14px; font-weight: 700;
  letter-spacing: 0.04em;
  border: 1px solid var(--borde-control); border-radius: 3px;
  background: transparent; color: var(--white);
  text-decoration: none; cursor: pointer;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: border-color .18s ease, background .18s ease, color .18s ease;
}
.btn:hover { border-color: var(--white); }
.btn:active { transform: translateY(1px); }

/* El acento MACIZO. El borde se declara aparte del fondo a propósito: en claro
   el lima no se distingue del papel (1,11:1) y es ese borde —acento tinta,
   5,70:1— el que le da frontera al botón. En oscuro borde y fondo coinciden. */
.btn--acento {
  background: var(--relleno);
  border-color: var(--relleno-borde);
  color: var(--relleno-tinta);
}
.btn--acento:hover {
  background: var(--relleno-h);
  border-color: var(--relleno-h);
  color: var(--relleno-h-tinta);
}

.btn--sobrio {
  min-height: 44px; padding: 10px 0; border: 0; border-radius: 0;
  font-family: var(--font-body); font-size: 14px; font-weight: 400;
  letter-spacing: 0; color: var(--muted);
  text-decoration: underline; text-decoration-color: var(--line-fuerte);
}
.btn--sobrio:hover { color: var(--white); text-decoration-color: currentColor; }

.btn--riesgo { border-color: var(--bad-borde); color: var(--bad); }
.btn--riesgo:hover { background: var(--bad); border-color: var(--bad); color: var(--black); }

/* ------------------------------------------------------------- entrada */

.entrada {
  min-height: 100dvh;
  display: grid;
  grid-template-columns: 1fr;
  align-content: start;
}

.entrada__marca {
  padding: var(--e4) var(--e3) var(--e3);
  border-bottom: 1px solid var(--line);
}
/* Logotipo a la izquierda, conmutador a la derecha. Envuelve en 320 px en vez
   de encogerse: el interruptor no puede bajar de sus 44 px de toque. */
.entrada__marca-fila {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e2); flex-wrap: wrap;
}

.entrada__caja { padding: var(--e5) var(--e3) var(--e6); }
.entrada__caja > * { max-width: 26rem; }

.volver {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 14px; color: var(--muted); text-decoration: none;
  touch-action: manipulation;
}
.volver:hover { color: var(--white); }

.logotipo {
  font-family: var(--font-display); font-weight: 800;
  font-size: 21px; letter-spacing: 0.16em; color: var(--white);
  text-decoration: none;
  /* Es un control suelto, no un enlace de prosa: 44 px de alto de toque. */
  display: inline-flex; align-items: center; min-height: 44px;
  touch-action: manipulation;
}
.logotipo span { color: var(--accent); }

.entrada h1 {
  font-size: clamp(30px, 8vw, 46px);
  margin-bottom: var(--e2);
}
.entrada__sub { color: var(--soft); margin-bottom: var(--e4); }

/* Atajo para quien ya tiene panel propio. Va antes del formulario y se
   distingue de el: si pareciera parte del formulario, nadie lo leeria. */
.entrada__atajo {
  margin: 18px 0 22px;
  padding: 13px 15px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--soft);
}
.entrada__atajo a { color: var(--acento); text-decoration: none; font-weight: 600; white-space: nowrap; }
.entrada__atajo a:hover { text-decoration: underline; }

.campo { display: block; margin-bottom: var(--e3); }
.campo > span {
  display: block; font-size: 12.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 7px;
}
.campo input {
  width: 100%; min-height: 48px; padding: 12px 14px;
  background: var(--grey); color: var(--white);
  border: 1px solid var(--borde-control); border-radius: 3px;
  font-family: var(--font-body); font-size: 16px;
}
.campo input::placeholder { color: var(--muted); }
.campo input:focus-visible { border-color: var(--accent); }

.aviso {
  border-left: 3px solid var(--bad);
  background: var(--bad-fondo);
  padding: var(--e2) var(--e3);
  margin-bottom: var(--e3);
  font-size: 15px;
}
.aviso--ok { border-left-color: var(--accent); background: var(--accent-dim); }
/* Aviso NEUTRO: para "aun no hay datos" y similares. Un "todavia no" no es
   una averia: ni filete ni fondo de error (lo pidio la revision del tema
   claro: en papel el rojo lavado hacia parecer roto lo que solo esta
   pendiente). */
.aviso--neutro { border-left-color: var(--borde-control); background: var(--grey); color: var(--soft); }
.aviso strong { font-family: var(--font-display); display: block; margin-bottom: 3px; }

.pie-legal {
  margin-top: var(--e5); padding-top: var(--e3);
  border-top: 1px solid var(--line);
  color: var(--muted); font-size: 13px;
}
.pie-legal a { color: var(--muted); }
.pie-legal a:hover { color: var(--white); }

@media (min-width: 900px) {
  .entrada {
    grid-template-columns: 1fr 1fr;
    align-content: stretch;
  }
  .entrada__marca {
    border-bottom: 0; border-right: 1px solid var(--line);
    padding: var(--e5) var(--e5);
    display: flex; flex-direction: column; justify-content: space-between;
  }
  .entrada__caja { padding: var(--e6) var(--e5); align-self: center; }
  .entrada__lema {
    font-family: var(--font-display); font-weight: 700;
    font-size: clamp(26px, 2.6vw, 38px); line-height: 1.15;
    letter-spacing: -0.02em; max-width: 14ch; margin-top: var(--e5);
  }
  .entrada__lema em { font-style: normal; color: var(--accent); }
}

/* --------------------------------------------------------------- armazón */

.hub { min-height: 100dvh; }

.hub__barra {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e2); flex-wrap: wrap;
  padding: var(--e2) var(--e3);
  border-bottom: 1px solid var(--line);
  background: var(--black);
}
.hub__barra form { margin: 0; }
/* Conmutador y «Cerrar sesión» en el mismo extremo de la barra. */
.hub__barra-fin {
  display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap;
}

.hub__cuerpo { display: block; }

.rail { padding: var(--e3); border-bottom: 1px solid var(--line); }
.rail__cliente {
  font-family: var(--font-display); font-weight: 800; font-size: 19px;
  letter-spacing: -0.01em;
}
.rail__meta { color: var(--muted); font-size: 13.5px; margin-top: 2px; }

.nav-hub { margin-top: var(--e3); }
/* En móvil las pestañas ENVUELVEN, no se van en un carrusel horizontal: un
   scroller lateral esconde la última pestaña y nadie la encuentra. */
.nav-hub ul { list-style: none; display: flex; flex-wrap: wrap; gap: var(--e1); }
.nav-hub a {
  display: flex; align-items: center; min-height: 44px; padding: 0 14px;
  white-space: nowrap; text-decoration: none;
  font-family: var(--font-display); font-size: 13.5px; font-weight: 600;
  letter-spacing: 0.04em; color: var(--soft);
  border: 1px solid var(--line); border-radius: 3px;
  touch-action: manipulation;
}
.nav-hub a:hover { color: var(--white); border-color: var(--line-fuerte); }
.nav-hub a[aria-current="page"] {
  color: var(--black); background: var(--accent); border-color: var(--accent);
}

.clara-enlace {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; margin-top: var(--e3); padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 3px;
  background: var(--accent-dim); color: var(--white);
  text-decoration: none; font-size: 14px;
}
.clara-enlace:hover { border-color: var(--accent); }
.clara-enlace b { font-family: var(--font-display); color: var(--accent); }
.clara-enlace span { color: var(--muted); font-size: 13px; }

.lienzo { padding: var(--e4) var(--e3) var(--e6); }

@media (min-width: 960px) {
  .hub__barra { padding: var(--e2) var(--e5); }
  .hub__cuerpo {
    display: grid;
    grid-template-columns: var(--rail) minmax(0, 1fr);
    align-items: start;
  }
  /* El filete que separa el raíl del contenido se pinta en el CONTENEDOR, no
     en el raíl: el raíl es sticky y su borde se quedaba a media página. */
  .hub__cuerpo {
    background-image: linear-gradient(to right,
      transparent 0 var(--rail),
      var(--line) var(--rail),
      var(--line) calc(var(--rail) + 1px),
      transparent calc(var(--rail) + 1px));
  }
  .rail {
    position: sticky; top: 0;
    border-bottom: 0;
    padding: var(--e4) var(--e3) var(--e4) var(--e5);
  }
  .nav-hub ul { flex-direction: column; flex-wrap: nowrap; gap: 2px; }
  .nav-hub a { border: 0; border-left: 2px solid transparent; border-radius: 0; padding-left: 12px; }
  .nav-hub a:hover { border-left-color: var(--line-fuerte); background: var(--grey); }
  .nav-hub a[aria-current="page"] {
    background: transparent; color: var(--accent);
    border-left-color: var(--accent);
  }
  .lienzo { padding: var(--e5) var(--e5) var(--e6) var(--e4); max-width: 74rem; }
}

/* ------------------------------------------------------------- saludo */

.saludo { margin-bottom: var(--e5); }
.saludo h1 {
  font-size: clamp(30px, 6.4vw, 52px);
  max-width: 18ch;
}
.saludo p {
  margin-top: var(--e2); color: var(--soft);
  font-size: clamp(16px, 2.2vw, 19px); max-width: 46ch;
}
.saludo b { color: var(--white); font-weight: 500; }

/* --------------------------------------------------- títulos de sección */

.rotulo {
  display: flex; align-items: baseline; gap: var(--e2);
  margin: var(--e5) 0 var(--e3);
  padding-bottom: var(--e1);
  border-bottom: 1px solid var(--line-fuerte);
}
.rotulo h2 {
  font-size: 13px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--white);
}
.rotulo p { color: var(--muted); font-size: 13px; margin-left: auto; text-align: right; }

.entradilla { color: var(--soft); max-width: 62ch; margin-bottom: var(--e4); }

/* ------------------------------------------------------------- módulos */

.modulos { border-top: 1px solid var(--line); }

.mod {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--e3);
  padding: var(--e3) 0;
  border-bottom: 1px solid var(--line);
}
.mod__nombre { font-size: clamp(21px, 4.4vw, 27px); }
.mod__nombre .mod__cat { display: none; }
/* El punto no envuelve: se queda arriba a la izquierda y el texto fluye a su
   lado. Con flex-wrap el texto largo se iba a la línea de abajo y el punto se
   quedaba solo. */
.mod__estado {
  margin-top: 6px; font-size: 14px; color: var(--muted);
  display: flex; align-items: flex-start; gap: 8px;
}
.mod__estado::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); flex: none; margin-top: 0.55em;
}
/* No activado: el punto se vacía. La forma cambia, no solo el color; y además
   lo pone escrito al lado, que es lo que de verdad informa. */
.mod__estado--off::before {
  background: transparent; box-shadow: inset 0 0 0 1px var(--muted);
}
.mod__texto { margin-top: var(--e1); color: var(--soft); max-width: 54ch; }

/* El no activado: más aire, la cifra grande y lo que incluye a la vista.
   Es el escaparate, y por eso pesa más que el activo. */
.mod--off { padding: var(--e4) 0 var(--e4); }
.mod--off .mod__nombre { font-size: clamp(25px, 6vw, 34px); }

.mod__incluye { list-style: none; margin-top: var(--e3); }
.mod__incluye li {
  position: relative; padding-left: 20px; margin-bottom: 6px;
  color: var(--soft); font-size: 15px;
}
.mod__incluye li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 9px; height: 1px; background: var(--accent);
}

.mod__accion { display: flex; flex-direction: column; align-items: flex-start; gap: var(--e2); }

.precio {
  font-family: var(--font-display); font-weight: 800;
  line-height: 0.92; letter-spacing: -0.03em; color: var(--accent);
  font-size: clamp(40px, 11vw, 58px);
  font-variant-numeric: tabular-nums;
}
.precio small {
  display: block; margin-top: 8px;
  font-family: var(--font-body); font-weight: 400; font-size: 14px;
  letter-spacing: 0; color: var(--muted);
}
/* El precio con IVA va pegado al de sin IVA, no como una nota suelta: es el que
   el cliente va a pagar y tiene que leerse de un tirón con el otro. */
.precio small + .precio__iva { margin-top: 2px; color: var(--soft); }

@media (min-width: 720px) {
  .mod {
    grid-template-columns: minmax(0, 1fr) minmax(190px, auto);
    gap: var(--e5);
    align-items: start;
  }
  .mod__accion { align-items: flex-end; text-align: right; }
  .precio small { text-align: right; }
}

.vacio {
  color: var(--muted); font-style: italic; padding: var(--e3) 0;
  border-bottom: 1px solid var(--line);
}

/* ------------------------------------------------------------ la ficha */

.ficha { max-width: 42rem; }
.ficha h1 { font-size: clamp(30px, 7vw, 46px); margin-bottom: var(--e2); }
.ficha__lead { color: var(--soft); font-size: 18px; margin-bottom: var(--e4); }

.ficha__precio {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: var(--e3) 0; border-top: 1px solid var(--line-fuerte);
  border-bottom: 1px solid var(--line);
}
.ficha__precio .precio { font-size: clamp(44px, 12vw, 64px); }

.ficha__bloque { padding: var(--e3) 0; border-bottom: 1px solid var(--line); }
.ficha__bloque h2 {
  font-size: 13px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted); margin-bottom: var(--e2);
}

.registro {
  background: var(--grey); border: 1px solid var(--line);
  border-radius: 3px; padding: var(--e3);
  font-size: 14.5px; color: var(--soft);
}
.registro dl { display: grid; grid-template-columns: 1fr; gap: 4px 18px; }
.registro dt { color: var(--muted); font-size: 12.5px; letter-spacing: 0.06em; text-transform: uppercase; }
.registro dd { margin-bottom: var(--e2); color: var(--white); }
.registro dd:last-child { margin-bottom: 0; }
@media (min-width: 620px) {
  .registro dl { grid-template-columns: 13rem minmax(0, 1fr); }
  .registro dt { padding-top: 2px; }
}

.ficha__acciones {
  display: flex; flex-wrap: wrap; gap: var(--e2); align-items: center;
  margin-top: var(--e4);
}
.ficha__nota { color: var(--muted); font-size: 14px; margin-top: var(--e2); max-width: 52ch; }

/* Consentimiento de ejecución inmediata + desistimiento. Ocupa la fila entera
   de .ficha__acciones y va ANTES del botón: primero se lee, luego se decide. */
.ficha__acciones .consentimiento { flex: 1 0 100%; }
.ficha__acciones .ficha__botones {
  flex: 1 0 100%;
  display: flex; flex-wrap: wrap; gap: var(--e2); align-items: center;
}
.casilla {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0 12px;
  align-items: start;
  padding: var(--e3); border: 1px solid var(--borde-control); border-radius: 3px;
  background: var(--grey); max-width: 62ch; cursor: pointer;
}
.casilla input[type="checkbox"] {
  /* 24 px reales: de esta casilla depende que el alta sea válida. */
  width: 24px; height: 24px; margin-top: 2px; accent-color: var(--accent);
}
.casilla span { color: var(--white); font-size: 15px; }
.casilla:hover { border-color: var(--accent); }
.consentimiento__nota {
  color: var(--soft); font-size: 14px; line-height: 1.55;
  margin-top: var(--e2); max-width: 62ch;
}

/* ------------------------------------------------------------- informes */

.lista { border-top: 1px solid var(--line); }
.lista__fila {
  display: grid; grid-template-columns: 1fr; gap: var(--e1);
  padding: var(--e3) 0; border-bottom: 1px solid var(--line);
}
.lista__fila h3 { font-size: 18px; font-weight: 600; }
.lista__meta { color: var(--muted); font-size: 13.5px; }
.lista__accion { justify-self: start; }
@media (min-width: 720px) {
  .lista__fila {
    grid-template-columns: 9.5rem minmax(0, 1fr) auto;
    gap: var(--e3); align-items: center;
  }
  .lista__meta { order: -1; font-variant-numeric: tabular-nums; }
  .lista__accion { justify-self: end; }
}

/* --------------------------------------------------------- estadísticas */

.dato-grande {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(38px, 9vw, 54px); line-height: 1;
  letter-spacing: -0.03em; color: var(--white);
  font-variant-numeric: tabular-nums;
}
.dato-grande + p { color: var(--muted); font-size: 14px; margin-top: 8px; }

.barras { margin-top: var(--e3); max-width: 34rem; }
.barra {
  display: grid; grid-template-columns: 5.4rem minmax(0, 1fr) 3.2rem;
  align-items: center; gap: 12px;
  padding: 5px 0;
  font-size: 14px;
}
.barra__k { color: var(--muted); }
.barra__v { text-align: right; font-variant-numeric: tabular-nums; color: var(--white); }
.barra__pista { height: 12px; background: var(--grey); border-radius: 2px; overflow: hidden; }
.barra__col {
  display: block; height: 100%; width: var(--w, 0%);
  background: var(--accent); border-radius: 0 2px 2px 0;
  min-width: 2px;
}

/* Demo: la barra se raya, no solo se apaga. La forma distingue, no el color, y
   la trama funciona igual en los dos temas porque va con --muted sobre la
   pista: 5,67:1 en oscuro y 5,67:1 en claro. El borde es de control, no
   decorativo, porque es lo que le da silueta a la barra rayada. */
.es-demo .barra__col {
  background: repeating-linear-gradient(
    135deg,
    var(--muted) 0 3px,
    transparent 3px 7px
  );
  border: 1px solid var(--borde-control);
  border-left: 0;
}
.es-demo .dato-grande, .es-demo .barra__v { color: var(--muted); }
/* En un bloque de ejemplo no queda ni un acento encendido: si el verde solo
   aparece en lo que es de verdad, la diferencia se ve de un vistazo. El dato
   sigue dicho con palabras, así que no se pierde nada al apagarlo.

   VA CON `.claves` DELANTE Y NO SE QUITA. Escrito como `.es-demo .mov--sube`
   empataba a 0-2-0 con `.claves .mov--sube` de más abajo, y en un empate gana
   la última: los movimientos de un bloque DEMO salían en verde de acento y en
   ámbar, como si fueran datos del cliente. Se veía en la captura, no en el
   CSS. Con `.claves` son 0-3-0 y ganan sin depender del orden del fichero. */
.es-demo .claves .mov--sube,
.es-demo .claves .mov--baja { color: var(--muted); }
.es-demo .mod__incluye li::before { background: var(--muted); }

.marca-demo {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display); font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--warn);
  border: 1px solid var(--warn); border-radius: 999px; padding: 3px 10px;
}

.bloque-stat { padding: var(--e4) 0; border-bottom: 1px solid var(--line); }
.bloque-stat:first-of-type { border-top: 1px solid var(--line); }
.bloque-stat h3 { font-size: clamp(20px, 4.4vw, 25px); }
.bloque-stat__cabeza {
  display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap;
  margin-bottom: var(--e1);
}
.bloque-stat__nota { color: var(--soft); max-width: 56ch; margin-top: 6px; }

.rejilla-stat { display: grid; grid-template-columns: 1fr; gap: var(--e4); margin-top: var(--e3); }
@media (min-width: 820px) {
  .rejilla-stat { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e5); }
}

.claves { list-style: none; margin-top: var(--e3); }
.claves li {
  display: grid; grid-template-columns: 3.4rem minmax(0, 1fr);
  gap: var(--e2); align-items: baseline;
  padding: 10px 0; border-top: 1px solid var(--line);
}
.claves .pos {
  font-family: var(--font-display); font-weight: 800; font-size: 26px;
  color: var(--white); font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.claves .term { font-size: 15px; }
.claves .mov { display: block; font-size: 13px; color: var(--muted); margin-top: 2px; }
.claves .mov--sube { color: var(--accent); }
.claves .mov--baja { color: var(--warn); }

.escaparate-stat {
  margin-top: var(--e3); padding-top: var(--e3);
  border-top: 1px dashed var(--line-fuerte);
  display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap;
}
.escaparate-stat p { color: var(--soft); font-size: 15px; max-width: 40ch; }

/* ------------------------------------------------------------ histórico */

.tabla-wrap { overflow-x: auto; }
table.historico { width: 100%; border-collapse: collapse; font-size: 14.5px; }
table.historico caption {
  text-align: left; color: var(--muted); font-size: 13.5px;
  padding-bottom: var(--e2);
}
/* En la vista de móvil la tabla pasa a display:block y el caption, que sigue
   siendo table-caption, se estrangula a una columna de dos palabras. */
@media (max-width: 700px) {
  table.historico caption { display: block; }
}
table.historico th, table.historico td {
  text-align: left; padding: 12px 16px 12px 0; border-bottom: 1px solid var(--line);
  vertical-align: top;
}
table.historico th {
  font-family: var(--font-body); font-weight: 500; font-size: 12px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
  border-bottom-color: var(--line-fuerte); white-space: nowrap;
}
table.historico td:first-child { font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
table.historico td.accion { font-family: var(--font-display); font-weight: 600; }
table.historico td.precio-visto { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Las condiciones que se enseñaron ese día: plegadas, pero en la página. */
/* El panel abre como CAPA, no empujando: si crece en flujo, la fila
   siguiente se mueve bajo el dedo de quien iba a pulsarla (Nico, 31/08). */
.condiciones-vistas { margin-top: 8px; position: relative; }
.condiciones-vistas summary {
  color: var(--muted); font-size: 13px; cursor: pointer;
  padding: 4px 0; /* zona de toque decente sin romper la fila */
}
.condiciones-vistas summary:hover { color: var(--white); }
.condiciones-vistas > div {
  position: absolute; left: 0; top: calc(100% + 4px); z-index: 40;
  padding: var(--e2);
  border: 1px solid var(--line-fuerte); border-left-width: 2px;
  background: var(--grey);
  color: var(--soft); font-size: 13.5px; line-height: 1.5;
  width: max-content; max-width: min(60ch, calc(100vw - 48px));
  white-space: normal;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .38);
}

@media (max-width: 700px) {
  table.historico, table.historico tbody, table.historico tr, table.historico td { display: block; width: 100%; }
  table.historico thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.historico tr { padding: var(--e3) 0; border-bottom: 1px solid var(--line); }
  table.historico td { border: 0; padding: 1px 0; }
  table.historico td::before {
    content: attr(data-col) " · "; color: var(--muted);
    font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase;
  }
  table.historico td.accion { font-size: 17px; margin-top: 2px; }
}

/* ------------------------------------------------- segundo factor (2FA) */
/* Las tres pantallas de index.php: alta con QR, códigos de un solo uso y el
   código de cada día. Viven dentro de `.entrada__caja`, así que heredan su
   ancho de 26 rem y no hay ni una regla de maquetación nueva.

   EL QR NO USA LOS TOKENS DEL TEMA A PROPÓSITO: se dibuja negro sobre blanco
   en los dos temas (lib/qr.php lo emite así) porque un QR en lima sobre negro
   no lo lee la mitad de las cámaras, y este se escanea una sola vez en la vida
   de la cuenta. La caja blanca de alrededor es su zona de silencio: sin ella,
   en tema oscuro el código acaba pegado al fondo negro y tampoco se lee. */

.pasos-2fa {
  margin: 0 0 var(--e3); padding-left: 1.4em;
  color: var(--soft); font-size: 15px; line-height: 1.6;
}
.pasos-2fa li { margin-bottom: 6px; }

/* La caja blanca ES la zona de silencio del QR: sin ella, en tema oscuro el
   codigo queda pegado al fondo negro y no hay lector que lo encuentre.
   El ancho tope es 240 px + 20 de relleno: cabe entero en 320 px de pantalla
   descontando el margen de `.entrada__caja` (22 px por lado), que es donde se
   colaba una barra de desplazamiento horizontal. */
.qr-caja {
  display: inline-block; padding: 10px; margin-bottom: var(--e3);
  max-width: 100%;
  background: #fff; border-radius: 3px;
  border: 1px solid var(--borde-control);
}
.qr-caja svg { display: block; width: 240px; max-width: 100%; height: auto; }

/* El secreto, para teclearlo a mano. Tipografía de ancho fijo y de cuatro en
   cuatro: es lo que hace que no se pierda la cuenta al copiarlo. */
.secreto {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 16px; letter-spacing: 0.08em; line-height: 1.7;
  color: var(--white); background: var(--grey);
  border: 1px solid var(--borde-control); border-radius: 3px;
  padding: var(--e2); margin-bottom: var(--e2);
  overflow-wrap: anywhere; user-select: all;
}
.secreto-pie { color: var(--muted); font-size: 13.5px; line-height: 1.6; margin-bottom: var(--e2); }
.secreto-pie strong { color: var(--soft); font-weight: 500; }

.ayuda { color: var(--muted); font-size: 13.5px; margin: -12px 0 var(--e3); }

/* El campo del código: seis cifras grandes y separadas, porque se teclean
   mirando el móvil y sin mirar la pantalla. */
.campo--codigo input {
  font-family: var(--font-display); font-size: 26px; font-weight: 700;
  letter-spacing: 0.28em; text-align: center;
  font-variant-numeric: tabular-nums;
  min-height: 60px; padding: 12px 8px;
}
.campo--codigo input::placeholder { letter-spacing: 0.28em; color: var(--muted); opacity: .45; }

.entrada .casilla { margin-bottom: var(--e3); padding: var(--e2); }
.entrada .casilla span { font-size: 14px; line-height: 1.5; }

.fila-salir { margin-top: var(--e2); }

/* Los ocho códigos de un solo uso. Dos columnas cuando caben: se leen de un
   vistazo y se copian sin saltarse ninguno. */
.respaldo-lista {
  list-style: none; margin: 0 0 var(--e3);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: 8px;
}
.respaldo-lista li {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 16px; letter-spacing: 0.06em; text-align: center;
  padding: 12px 6px; background: var(--grey);
  border: 1px solid var(--borde-control); border-radius: 3px;
  color: var(--white); user-select: all;
}

/* «No tengo el móvil»: plegado, pero en la página y sin JavaScript. */
.apuro { margin-top: var(--e3); border-top: 1px solid var(--line); padding-top: var(--e2); }
.apuro summary {
  color: var(--muted); font-size: 14px; cursor: pointer;
  min-height: 44px; display: flex; align-items: center;
}
.apuro summary:hover { color: var(--white); }
.apuro p { color: var(--soft); font-size: 14px; line-height: 1.6; margin-bottom: var(--e2); }

/* ------------------------------------------------------------------ pie */

.pie-hub {
  margin-top: var(--e6); padding-top: var(--e3);
  border-top: 1px solid var(--line);
  color: var(--muted); font-size: 13px; max-width: 62ch;
}
.pie-hub a { color: var(--muted); }
.pie-hub a:hover { color: var(--white); }

/* Bloque legal: mismo tono en el área y bajo el login. */
.pie-legal-hub {
  margin-top: var(--e2); color: var(--muted); font-size: 12.5px;
  line-height: 1.7; max-width: 68ch;
}
.pie-legal-hub a { color: var(--muted); }
.pie-legal-hub a:hover { color: var(--white); }
.entrada .pie-legal-hub { margin-top: var(--e3); }

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