/* public/css/app.css — TODO el estilo de la libreta.
 *
 * Salió del bloque <style> de public/index.html el 28-oct, tal cual:
 * ni una regla cambiada, ni una reordenada. Era mudanza, no rediseño.
 *
 * El orden IMPORTA y es el de siempre: la cascada manda, y hay capas al
 * final de este archivo que ganan a propósito por venir después (busca
 * "va al final"). Si algún día esto se parte en varios archivos, tienen
 * que enlazarse EN ESTE MISMO ORDEN.
 *
 * Lo que NO está aquí: el <style> que se arma dentro del JavaScript para
 * la ventana de impresión del recibo, y la hoja de variables del tema que
 * se inyecta desde app.js. Esos viven donde viven porque se generan.
 */
    /* ── Reset & Variables ─────────────────────────────────────────────── */
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

    :root {
      /* ═══════════════════════════════════════════════════════════════
         EL ORDEN DE LAS CAPAS — quién tapa a quién, en un solo sitio
      ═══════════════════════════════════════════════════════════════════

         De abajo arriba. Cada número vive AQUÍ y sólo aquí: si una capa
         nueva necesita colarse entre dos, se le pone nombre en esta lista
         y no se improvisa un 9999 suelto en mitad de la hoja.

           480     un panel dentro de una pantalla (#bg-panel)
           500     las pantallas que se abren encima (los "overlay")
           520     pendientes de pago, que se abre desde varias
           550     historial de cambios
           560     cédula/cliente, que sale desde registrar
           600     pedir la contraseña
           700     pedir la contraseña dentro de registrar
          1000     la pantalla de entrada
          9000     el VISOR DE FOTOS: encima de cualquier pantalla, porque
                   se abre desde dentro de ellas
          9500     el globo de ayuda
          9800     el cartel del turno abierto
          9850     el cartel del cobro de WispHub
          9999     avisos que no tapan nada importante (toast, versión)
         10000     la portada de bienvenida
        100000     la sesión bloqueada — por encima de todo, siempre

         ── LA TRAMPA QUE COSTÓ UN FALLO ─────────────────────────────
         #app lleva `position:relative; z-index:1` (para quedar sobre el
         fondo de la página). Eso lo convierte en un MUNDO APARTE: un
         elemento de dentro, por mucho z-index que declare, nunca sube por
         encima de otro que viva fuera. El visor de fotos estaba dentro de
         #app con z-index 99999 y aun así se abría POR DETRÁS del detalle
         de una transacción, que es un overlay de 500 colgado del body.

         Regla, entonces: todo lo que tenga que taparlo TODO va colgado
         del <body>, nunca de #app. (Queda un caso vivo del mismo tipo:
         .disp-modal-backdrop declara 9999 dentro de #app, así que su 9999
         no vale fuera. No molesta porque no se abre junto a nada de
         fuera, pero si algún día hay que sacarlo, es por esto.)
      */
      --capa-panel:          480;
      --capa-modal:          500;
      --capa-modal-pend:     520;
      --capa-modal-hist:     550;
      --capa-modal-ci:       560;
      --capa-modal-clave:    600;
      --capa-login:         1000;
      --capa-chat:          8800;
      --capa-visor:         9000;
      --capa-ayuda:         9500;
      --capa-cartel-turno:  9800;
      --capa-cartel-cobro:  9850;
      --capa-aviso:         9999;
      --capa-intro:        10000;
      --capa-bloqueo:     100000;

      /* ── Paleta nueva (dark + oro) ───────────────────────────────── */
      --bg-base:        #0a0a0c;
      --bg-elevated:    #16161a;
      --bg-card:        #1a1a20;
      --bg-input:       #0f0f13;
      --bg-overlay:     rgba(10, 10, 12, 0.85);

      --bg-gold-start:  #2a1f0d;
      --bg-gold-end:    #3d2e10;
      --bg-gold-grad:   linear-gradient(135deg, #2a1f0d 0%, #3d2e10 100%);

      --border-subtle:  rgba(255, 255, 255, 0.06);
      --border-soft:    rgba(255, 255, 255, 0.10);
      --border-strong:  rgba(255, 255, 255, 0.18);
      --border-accent:  #3b6a96;
      --border-gold:    rgba(201, 169, 97, 0.35);

      --gold:           #c9a961;
      --gold-bright:    #e5c878;
      --gold-dim:       #8a7842;
      --rose:           #b88a8a;
      --rose-bg:        #2a1818;
      --cyan-accent:    #5a8fb8;

      --positive:       #5ab574;
      --positive-bg:    rgba(90, 181, 116, 0.12);
      --negative:       #d97474;
      --negative-bg:    rgba(217, 116, 116, 0.12);
      --warning:        #e5a05e;

      --text-primary:   #ffffff;
      --text-secondary: #c0c0c8;
      --text-muted:     #8a8a92;
      --text-dim:       #5a5a64;
      --text-on-gold:   #f5e8c8;

      --font-serif:     'Playfair Display', Georgia, serif;
      --font-sans:      'Inter', -apple-system, system-ui, sans-serif;

      --radius-sm:      8px;
      --radius-md:      14px;
      --radius-lg:      20px;
      --shadow-card:    0 1px 3px rgba(0,0,0,0.4), 0 4px 12px rgba(0,0,0,0.2);
      --shadow-gold:    0 4px 24px rgba(201, 169, 97, 0.12);

      /* ── Aliases heredados (legacy claritas) ─────────────────────────
         Las reglas viejas siguen usando estos nombres; aquí los re-mapeo
         al tema oscuro para evitar tocar ~100 referencias una por una. */
      --rose-light:  var(--bg-base);
      --rose-mid:    var(--bg-elevated);
      --rose-deep:   var(--gold);
      --rose-med:    var(--gold);
      --gold-light:  var(--gold-bright);
      --gold-dark:   var(--gold-dim);
      --text-dark:   var(--text-primary);
      --text-med:    var(--text-secondary);
      --white:       var(--bg-card);
      --border:      var(--border-subtle);
      --radius:      var(--radius-md);
      --shadow:      var(--shadow-card);
      --shadow-lg:   var(--shadow-card);

      /* Layout (sin cambios) */
      --topbar-h:    64px;
    }

    html, body { height: 100%; overflow: hidden; }

    body {
      font-family: var(--font-sans);
      background: var(--rose-light);
      color: var(--text-dark);
      font-size: 15px;
      display: flex;
    }

    /* ── Scrollbar ──────────────────────────────────────────────────────── */
    ::-webkit-scrollbar { width: 6px; height: 6px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: var(--rose-deep); border-radius: 99px; }

    /* ═══════════════════════════════════════════════════════════════════
       SIDEBAR
    ══════════════════════════════════════════════════════════════════════ */

    .nav-item {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 10px 14px;
      border-radius: var(--radius-sm);
      cursor: pointer;
      color: rgba(255,255,255,0.6);
      font-size: 0.88rem;
      font-weight: 400;
      transition: all 0.18s;
      margin-bottom: 2px;
      user-select: none;
    }
    .nav-item:hover {
      background: rgba(232,160,176,0.1);
      color: rgba(255,255,255,0.9);
    }
    .nav-item.active {
      background: linear-gradient(135deg, rgba(232,160,176,0.25), rgba(201,169,110,0.15));
      color: var(--white);
      font-weight: 500;
    }
    .nav-item.active .nav-icon { color: var(--rose-deep); }
    .nav-icon {
      width: 18px;
      text-align: center;
      font-size: 16px;
      flex-shrink: 0;
      color: rgba(255,255,255,0.4);
      transition: color 0.18s;
    }

    /* Badge dorado para contador (pendientes por autorización). */
    .nav-badge {
      margin-left: auto;
      background: var(--bg-gold-grad);
      border: 1px solid var(--gold);
      color: var(--gold-bright);
      font-size: 0.72rem;
      font-weight: 700;
      padding: 1px 8px;
      border-radius: 999px;
      min-width: 22px;
      text-align: center;
      box-shadow: 0 0 0 2px rgba(201,169,97,0.18);
    }

    /* ── Vista Disponibles (saldos por persona) ────────────────────── */
    .disp-persona-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 14px;
      margin-bottom: 24px;
    }
    /* Etiqueta de grupo de cuentas por moneda (Bolívares / USDT) */
    .disp-group-label {
      font-size: 0.72rem;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--text-muted);
      margin: 4px 0 10px;
    }
    .disp-persona-card.usdt { border-color: rgba(90,181,116,.45); }
    .disp-persona-card {
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      padding: 16px 18px;
      cursor: pointer;
      transition: transform .15s, border-color .15s, background .15s;
      position: relative;
    }
    .disp-persona-card:hover { transform: translateY(-1px); }
    /* Cuenta desactivada: se sigue viendo y se puede abrir (para consultarla
       o volver a activarla), pero apagada, para que no se confunda con las
       que se usan hoy. */
    .disp-persona-card.inactiva {
      opacity: .55;
      border-style: dashed;
      border-color: var(--linea);
    }
    .disp-persona-card.inactiva:hover { opacity: .8; }
    /* Y si se abre una desactivada para mirarla, se marca que está abierta
       sin encenderla: el dorado macizo de .selected la haría parecer la
       cuenta con la que se está trabajando, que es justo lo contrario. */
    /* Al abrirla se le quita el apagado y se la deja con el mismo realce que
       cualquier otra card abierta: el texto de una card seleccionada está
       pensado para ese fondo dorado, y sobre uno apagado se vuelve
       ilegible. Lo que dice que está fuera de uso es su rótulo
       "Desactivada", que se sigue leyendo. */
    .disp-persona-card.inactiva.selected { opacity: 1; }
    .disp-persona-card.selected {
      background: var(--oro-macizo);
      border-color: var(--gold);
      box-shadow: 0 0 0 1px var(--gold);
    }
    .disp-persona-card.principal {
      border-style: dashed;
      border-color: var(--gold-bright);
    }
    .disp-persona-card.principal.selected {
      border-style: solid;
    }
    .disp-persona-card-badge {
      display: inline-block;
      background: rgba(229,200,120,0.18);
      color: var(--gold-bright);
      font-size: 0.62rem;
      font-weight: 600;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      padding: 2px 8px;
      border-radius: 999px;
      margin-bottom: 6px;
    }
    .disp-persona-card-sub {
      font-size: 0.66rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      margin-top: 4px;
    }
    .disp-persona-card-name {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold-bright);
      font-size: 16.8px;
      margin-bottom: 6px;
    }
    .disp-persona-card-saldo {
      font-family: var(--font-sans);
      font-weight: 700;
      color: var(--text-primary);
      font-size: 20px;
      letter-spacing: -0.01em;
    }
    .disp-persona-card-saldo small {
      font-size: 0.7rem;
      color: var(--text-muted);
      font-weight: 400;
      margin-right: 4px;
    }
    .disp-edit-btn {
      position: absolute;
      top: 8px;
      right: 8px;
      width: 24px;
      height: 24px;
      padding: 0;
      border: 1px solid var(--border-soft);
      background: var(--bg-elevated);
      color: var(--text-muted);
      border-radius: 6px;
      font-size: 0.78rem;
      line-height: 1;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .disp-edit-btn:hover { color: var(--gold-bright); border-color: var(--border-gold); }
    .disp-del-btn {
      position: absolute;
      top: 8px;
      right: 38px;
      width: 24px;
      height: 24px;
      padding: 0;
      border: 1px solid var(--border-soft);
      background: var(--bg-elevated);
      color: var(--text-muted);
      border-radius: 6px;
      font-size: 0.78rem;
      line-height: 1;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .disp-del-btn:hover { color: var(--negative); border-color: var(--negative); }
    .disp-persona-card-add {
      background: transparent;
      border: 1px dashed var(--border-soft);
      border-radius: var(--radius);
      padding: 16px 18px;
      cursor: pointer;
      color: var(--text-muted);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 4px;
      min-height: 84px;
      transition: color .15s, border-color .15s;
    }
    .disp-persona-card-add:hover { color: var(--gold-bright); border-color: var(--border-gold); }
    .disp-persona-card-add .add-plus { font-size: 22.4px; line-height: 1; }
    .disp-persona-card-add .add-label { font-size: 0.78rem; }
    .disp-hero {
      background: var(--bg-gold-grad);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      padding: 28px 32px;
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
    }
    .disp-hero-label {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold);
      font-size: 0.78rem;
      letter-spacing: 0.18em;
      margin-bottom: 8px;
    }
    .disp-hero-value {
      font-family: var(--font-sans);
      font-weight: 700;
      color: var(--text-primary);
      font-size: 38.4px;
      line-height: 1.1;
      letter-spacing: -0.02em;
    }
    .disp-hero-name {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold-bright);
      font-size: 16px;
      margin-top: 8px;
    }
    .disp-hero-btn {
      position: absolute;
      top: 20px;
      right: 20px;
    }
    .disp-kpis {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 14px;
      margin-top: 18px;
    }
    .disp-kpi {
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      padding: 14px 18px;
    }
    .disp-kpi-label {
      font-size: 0.72rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      margin-bottom: 6px;
    }
    .disp-kpi-value {
      font-family: var(--font-sans);
      font-weight: 700;
      font-size: 17.6px;
    }
    /* Modal recarga */
    .disp-modal-backdrop {
      position: fixed;
      inset: 0;
      background: rgba(0,0,0,0.6);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: var(--capa-aviso);          /* OJO: vive dentro de #app, así que este 9999 no vale fuera. Ver EL ORDEN DE LAS CAPAS. */
      padding: 20px;
    }
    .disp-modal {
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      padding: 24px 28px;
      width: 100%;
      max-width: 440px;
      box-shadow: 0 20px 60px rgba(0,0,0,0.5);
    }
    .disp-modal-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 16px;
    }
    .disp-modal-title {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold-bright);
      font-size: 18.4px;
    }
    .disp-modal-title span { color: var(--text-primary); font-style: normal; }
    .disp-modal-close {
      background: transparent;
      border: none;
      color: var(--text-muted);
      cursor: pointer;
      font-size: 19.2px;
      line-height: 1;
    }
    .disp-modal-close:hover { color: var(--gold); }
    /* Registro de Ingresos — botones de categoría */
    .ing-cat-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 14px;
      margin-top: 8px;
    }
    .ing-cat-btn {
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      padding: 22px 16px;
      cursor: pointer;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 12px;
      color: inherit;
      text-align: center;
      font-family: inherit;
      transition: transform .15s, border-color .15s, background .15s;
    }
    .ing-cat-btn:hover {
      transform: translateY(-1px);
      border-color: var(--gold);
    }
    .ing-cat-btn.selected {
      background: var(--bg-gold-grad);
      border-color: var(--gold);
      box-shadow: 0 0 0 1px var(--gold);
    }
    .ing-cat-icon {
      font-size: 28.8px;
      color: var(--gold-bright);
      line-height: 1;
    }
    /* Categorías creadas desde la app: su ícono es un SVG del catálogo. */
    .ing-cat-icon svg {
      width: 30px;
      height: 30px;
      display: block;
      stroke: var(--gold-bright);
      color: var(--gold-bright);
    }
    .ing-cat-label {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--text-primary);
      font-size: 0.95rem;
    }

    /* ── Pago Móvil (detalle dentro de Registro de Ingresos) ─────────── */
    .pm-header {
      display: flex;
      align-items: center;
      gap: 16px;
      margin-bottom: 16px;
    }
    .pm-header h3 {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold-bright);
      font-size: 20px;
      margin: 0;
    }
    .pm-total {
      margin-left: auto;
      padding: 6px 14px;
      background: var(--bg-gold-grad);
      border: 1px solid var(--border-gold);
      border-radius: 999px;
      color: var(--gold-bright);
      font-weight: 600;
      font-size: 0.85rem;
      white-space: nowrap;
    }
    .pm-resumen {
      display: flex;
      flex-wrap: wrap;
      gap: 8px 14px;
      align-items: baseline;
      padding: 10px 14px;
      margin-bottom: 12px;
      background: rgba(201,169,97,0.06);
      border: 1px solid var(--border-gold);
      border-left-width: 3px;
      border-radius: 8px;
      font-size: 0.88rem;
    }
    .pm-resumen-item { display: inline-flex; gap: 6px; align-items: baseline; }
    .pm-resumen-k { color: var(--text-muted); font-weight: 600; }
    .pm-resumen-v { color: var(--text-primary); font-weight: 600; }
    .pm-resumen-v.gold {
      color: var(--gold-bright);
      font-family: var(--font-sans);
      font-weight: 700;
      font-size: 16.8px;
      letter-spacing: 0.01em;
      font-variant-numeric: tabular-nums;
    }
    .pm-resumen-sep { color: var(--text-dim); }
    .pm-filters {
      display: flex;
      flex-wrap: wrap;
      align-items: end;
      gap: 12px;
      padding: 14px 16px;
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      margin-bottom: 16px;
    }
    .pm-filters .pm-field { display: flex; flex-direction: column; gap: 4px; }
    .pm-filters label {
      font-size: 0.72rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
    }
    .pm-filters input[type="date"] {
      background: var(--bg-dark, #0d0d12);
      border: 1px solid var(--border-gold);
      color: var(--text-primary);
      padding: 6px 10px;
      border-radius: 6px;
      font-family: var(--font-sans);
      font-size: 0.85rem;
      color-scheme: dark;
    }
    .pm-filters input[type="date"]:focus { border-color: var(--gold); }

    /* Filtro de fecha: "Un día" o "Por rango", nunca los dos a la vez. Los
       botones son los MISMOS de Informes (.inf-modo), en chico: el operador
       ya conoce el gesto y no tiene que aprender otro. El lado que no manda
       queda atenuado y desactivado — no se puede rellenar por error ni dejar
       un valor viejo decidiendo por él. */
    .pm-filters .inf-modos { margin-bottom: 0; gap: 6px; }
    .pm-filters .inf-modo { font-size: 13px; padding: 6px 14px; }
    .pm-field.apagado { opacity: .45; }
    .pm-field.apagado input[type="date"] { cursor: not-allowed; }
    .pm-split {
      display: grid;
      grid-template-columns: 1fr 360px;
      gap: 16px;
      align-items: start;
    }
    @media (max-width: 900px) {
      .pm-split { grid-template-columns: 1fr; }
    }
    .pm-table-wrap {
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      overflow: hidden;
    }
    .pm-table-wrap table {
      width: 100%;
      border-collapse: collapse;
    }
    .pm-table-wrap thead th {
      text-align: left;
      font-size: 0.72rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      padding: 10px 14px;
      background: rgba(0,0,0,0.25);
      border-bottom: 1px solid var(--border-gold);
    }
    .pm-table-wrap tbody tr {
      border-bottom: 1px solid rgba(201,169,97,0.10);
      cursor: pointer;
      transition: background .15s, border-color .15s;
    }
    .pm-table-wrap tbody tr:hover { background: rgba(201,169,97,0.04); }
    .pm-table-wrap tbody tr.selected {
      background: rgba(201,169,97,0.08);
      box-shadow: inset 2px 0 0 var(--gold);
    }
    .pm-table-wrap td {
      padding: 10px 14px;
      font-size: 0.88rem;
      color: #e5e5e5;
    }
    .pm-panel {
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
      padding: 18px 20px;
      position: sticky;
      top: 16px;
    }
    .pm-panel-empty {
      color: var(--text-muted);
      font-size: 0.88rem;
      text-align: center;
      padding: 28px 12px;
    }
    .pm-panel h4 {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold-bright);
      font-size: 16.8px;
      margin: 0 0 12px 0;
    }
    .pm-panel .pm-field-row {
      display: flex;
      justify-content: space-between;
      gap: 12px;
      padding: 6px 0;
      border-bottom: 1px dashed rgba(201,169,97,0.12);
      font-size: 0.85rem;
    }
    .pm-panel .pm-field-row:last-of-type { border-bottom: none; }
    .pm-panel .pm-field-label {
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.06em;
      font-size: 0.7rem;
    }
    .pm-panel .pm-field-value {
      color: var(--text-primary);
      font-family: var(--font-sans);
      text-align: right;
      word-break: break-word;
    }
    .pm-thumb {
      display: block;
      max-width: 100%;
      width: 120px;
      height: 90px;
      object-fit: cover;
      border-radius: 6px;
      border: 1px solid var(--border-gold);
      cursor: pointer;
      margin: 0 auto 14px auto;
    }
    .pm-thumb:hover { border-color: var(--gold); }
    .pm-no-photo {
      text-align: center;
      color: var(--text-muted);
      font-size: 0.8rem;
      padding: 16px;
      border: 1px dashed rgba(201,169,97,0.2);
      border-radius: 6px;
      margin-bottom: 14px;
    }
    .pm-edit-btn {
      margin-top: 14px;
      width: 100%;
      padding: 8px 14px;
      background: transparent;
      border: 1px solid var(--border-gold);
      color: var(--gold-bright);
      border-radius: 6px;
      font-family: inherit;
      cursor: pointer;
    }
    .pm-edit-btn[disabled] {
      opacity: 0.5;
      cursor: not-allowed;
    }
    .pm-delete-btn {
      margin-top: 8px;
      width: 100%;
      padding: 8px 14px;
      background: transparent;
      border: 1px solid var(--negative);
      color: var(--negative);
      border-radius: 6px;
      font-family: inherit;
      cursor: pointer;
      transition: background .12s;
    }
    .pm-delete-btn:hover {
      background: rgba(215,119,119,0.08);
    }
    .pm-edit-row {
      display: flex;
      flex-direction: column;
      gap: 6px;
      margin-top: 14px;
    }
    .pm-edit-row .pm-edit-btn { margin-top: 0; }
    .pm-history-link {
      display: inline-block;
      align-self: center;
      color: var(--text-secondary);
      text-decoration: underline;
      cursor: pointer;
      font-size: 0.78rem;
    }
    .pm-history-link:hover { color: var(--gold-bright); }

    /* ── Lote B: modales de edición / autorización / historial ────────── */
    .edit-form-grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
    }
    .edit-form-grid .form-group.full { grid-column: 1 / -1; }
    .edit-thumb-wrap {
      display: flex;
      gap: 12px;
      margin-bottom: 14px;
      flex-wrap: wrap;
    }
    .edit-thumb-wrap img {
      width: 90px;
      height: 90px;
      object-fit: cover;
      border-radius: 6px;
      border: 1px solid var(--border-soft);
    }
    .edit-thumb-note {
      font-size: 0.72rem;
      color: var(--text-muted);
      align-self: center;
    }
    #auth-overlay .modal {
      border-top: 3px solid var(--warning);
      max-width: 380px;
    }
    #auth-overlay .auth-note {
      color: var(--warning);
      font-size: 0.82rem;
      margin-bottom: 12px;
    }
    .audit-table {
      width: 100%;
      border-collapse: collapse;
      font-size: 0.82rem;
    }
    .audit-table th, .audit-table td {
      padding: 8px 10px;
      border-bottom: 1px solid var(--border-subtle);
      text-align: left;
      vertical-align: top;
    }
    .audit-table th {
      color: var(--text-muted);
      font-weight: 500;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      font-size: 0.68rem;
    }
    .audit-table .val-anterior { color: var(--negative); }
    .audit-table .val-nuevo    { color: var(--positive); }
    .audit-empty {
      padding: 28px;
      text-align: center;
      color: var(--text-muted);
    }
    .toast {
      position: fixed;
      bottom: 24px;
      left: 50%;
      transform: translateX(-50%);
      background: var(--bg-elevated);
      color: var(--positive);
      border: 1px solid var(--border-soft);
      border-radius: var(--radius-md);
      padding: 10px 18px;
      box-shadow: var(--shadow-card);
      z-index: var(--capa-aviso);
      font-size: 0.88rem;
      opacity: 0;
      transition: opacity .25s ease;
      pointer-events: none;
    }
    .toast.show { opacity: 1; }
    .toast.error { color: var(--negative); border-color: var(--negative-bg); }

    /* ── Lote C: admin-only + panel de precios + estado discrepancia ── */
    body:not(.is-admin) .admin-only { display: none !important; }
    body.is-admin .operator-only { display: none !important; }
    .acceso-restringido {
      max-width: 480px;
      margin: 60px auto;
      padding: 32px;
      background: var(--bg-card);
      border: 1px solid var(--border-soft);
      border-radius: var(--radius-md);
      text-align: center;
    }
    .acceso-restringido h3 { color: var(--warning); margin: 0 0 12px; }
    .acceso-restringido p  { color: var(--text-muted); margin: 0; }

    .precios-wrap { max-width: 920px; }
    .precios-wrap h3 { margin: 0 0 4px; }
    .precios-wrap .precios-sub {
      color: var(--text-muted);
      font-size: 0.86rem;
      margin-bottom: 22px;
    }

    /* ── Panel jerárquico de Precios (Sprint lunes 8 jun) ──────────────── */
    .precios-list {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
    .precios-card {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-left: 3px solid var(--gold-dim);
      border-radius: var(--radius-md);
      overflow: hidden;
    }
    .precios-card.expanded { border-left-color: var(--gold-bright); }
    .precios-empty-folder {
      padding: 8px 0;
      color: var(--text-muted);
      font-size: 0.84rem;
      font-style: italic;
    }
    .precios-card-head {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 12px 16px;
      cursor: pointer;
      transition: background .15s;
    }
    .precios-card-head:hover { background: var(--bg-elevated); }
    .precios-card-caret {
      width: 18px;
      color: var(--gold-dim);
      font-size: 14px;
      transition: transform .15s;
      display: inline-block;
      text-align: center;
    }
    .precios-card.expanded .precios-card-caret { transform: rotate(90deg); }
    .precios-card-titles {
      flex: 1;
      min-width: 0;
    }
    .precios-card-title {
      font-size: 0.98rem;
      font-weight: 600;
      color: var(--text-primary);
    }
    .precios-card-sub {
      font-size: 0.78rem;
      color: var(--text-muted);
      margin-top: 2px;
    }
    .precios-card-actions {
      display: flex;
      gap: 6px;
    }
    .precios-card-actions .btn-mini {
      padding: 4px 10px;
      font-size: 0.74rem;
      background: var(--bg-elevated);
      border: 1px solid var(--border-soft);
      border-radius: 6px;
      color: var(--text-primary);
      cursor: pointer;
    }
    .precios-card-actions .btn-mini:hover { background: var(--bg-card); }
    .precios-card-actions .btn-mini.danger {
      color: var(--negative);
      border-color: rgba(215,119,119,0.35);
    }
    .precios-card-body {
      display: none;
      padding: 4px 16px 14px 50px;
      border-top: 1px solid var(--border-subtle);
    }
    .precios-card.expanded .precios-card-body { display: block; }
    .precios-subitem-row {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 8px 0;
      border-bottom: 1px dashed var(--border-subtle);
    }
    .precios-subitem-row:last-child { border-bottom: none; }
    .precios-subitem-name {
      flex: 1;
      font-size: 0.92rem;
    }
    .precios-subitem-price {
      font-family: var(--font-serif);
      color: var(--gold-bright);
      font-size: 0.98rem;
      min-width: 80px;
      text-align: right;
    }
    .precios-add-sub {
      margin-top: 10px;
      padding: 6px 12px;
      font-size: 0.8rem;
      background: transparent;
      border: 1px dashed var(--border-soft);
      border-radius: 6px;
      color: var(--gold-bright);
      cursor: pointer;
    }
    .precios-add-sub:hover { background: var(--bg-elevated); }

    .badge {
      display: inline-block;
      padding: 2px 10px;
      border-radius: 999px;
      font-size: 0.72rem;
      font-weight: 600;
      letter-spacing: 0.04em;
    }
    .badge-ok    { background: var(--positive-bg); color: var(--positive); }
    .badge-disc  { background: var(--negative-bg); color: var(--negative); }
    /* "Ponle el ojo": ni bien ni mal. Hoy lo usa la mensualidad que entró
       por el céntimo de tolerancia, y sólo lo ve el admin. */
    .badge-ojo   { background: rgba(229, 160, 94, 0.14); color: var(--warning);
                   cursor: help; }

    .sv-total-card {
      background: var(--bg-gold-grad);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius-md);
      padding: 18px 22px;
      margin-bottom: 18px;
      box-shadow: var(--shadow-gold);
    }
    .sv-total-card .sv-total-label {
      font-size: 0.72rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--gold-bright);
      margin-bottom: 4px;
    }
    .sv-total-card .sv-total-value {
      font-family: var(--font-serif);
      font-size: 32px;
      color: var(--gold-bright);
    }
    .sv-disc-alert {
      background: var(--negative-bg);
      border: 1px solid var(--negative);
      color: var(--negative);
      padding: 10px 14px;
      border-radius: 6px;
      margin: 12px 0;
      font-size: 0.86rem;
    }
    /* Mismo cuadro, en ámbar: no es un descuadre, es un "míralo". */
    .sv-disc-alert.sv-disc-ojo {
      background: rgba(229, 160, 94, 0.12);
      border-color: var(--warning);
      color: var(--warning);
    }
    .pm-empty-state {
      padding: 40px 20px;
      text-align: center;
      color: var(--text-muted);
    }
    .pm-empty-state .pm-empty-icon {
      font-size: 32px;
      color: var(--gold-dim);
      margin-bottom: 8px;
    }

    /* Pago Listo: panel con DOS miniaturas (báscula + comprobante) */
    .pl-thumbs {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 10px;
      margin-bottom: 14px;
    }
    .pl-thumb-cell {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 6px;
    }
    .pl-thumb-label {
      font-size: 0.68rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
    }
    .pl-thumb-cell .pm-thumb,
    .pl-thumb-cell .pm-no-photo {
      margin: 0;
      width: 100%;
      height: 80px;
    }
    .pl-thumb-cell .pm-no-photo {
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 8px;
      font-size: 0.72rem;
    }

    /* Placeholder "Próximamente" para categorías sin implementar */
    .ing-placeholder {
      text-align: center;
      padding: 60px 20px;
      color: var(--text-muted);
      background: var(--bg-card);
      border: 1px solid var(--border-gold);
      border-radius: var(--radius);
    }
    .ing-placeholder .ing-placeholder-icon {
      font-size: 38.4px;
      color: var(--gold-dim);
      margin-bottom: 12px;
    }
    .ing-placeholder h3 {
      font-family: var(--font-serif);
      font-style: italic;
      color: var(--gold-bright);
      font-size: 20px;
      margin: 0 0 6px;
    }
    .ing-placeholder p {
      font-size: 0.9rem;
      margin: 0;
    }

    /* Lightbox para fotos.
       El hueco de arriba es para la ✕: antes el botón caía ENCIMA de la
       foto, y en una foto vertical de teléfono tapaba justo la esquina. */
    #pm-lightbox {
      position: fixed;
      inset: 0;
      background: rgba(0,0,0,0.92);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: var(--capa-visor);
      padding: 72px 20px 24px;
    }
    /* 100% del hueco que deja el padding, no 90vw/90vh: así la foto entra
       ENTERA, que es lo que se viene a mirar. Sin object-fit que recorte y
       respetando la marca de orientación del archivo. */
    #pm-lightbox img {
      max-width: 100%;
      max-height: 100%;
      width: auto;
      height: auto;
      object-fit: contain;
      image-orientation: from-image;
      box-shadow: 0 20px 60px rgba(0,0,0,0.7);
      border-radius: 4px;
    }
    #pm-lightbox-fallo {
      color: #e8e2d8;
      font-size: 1rem;
      text-align: center;
      padding: 24px 20px;
      border: 1px dashed rgba(255,255,255,0.25);
      border-radius: 10px;
    }
    .pm-lightbox-close {
      position: absolute;
      top: 16px;
      right: 20px;
      z-index: 1;
      background: rgba(255,255,255,0.08);
      border: none;
      color: #fff;
      font-size: 25.6px;
      line-height: 1;
      cursor: pointer;
      width: 44px;
      height: 44px;
      border-radius: 50%;
      transition: background .15s;
    }
    .pm-lightbox-close:hover { background: rgba(255,255,255,0.2); }
    /* Los mandos de la lupa. Arriba a la izquierda, lejos de la ✕. */
    .pm-lightbox-zoom {
      position: absolute;
      top: 16px;
      left: 20px;
      z-index: 2;
      display: flex;
      align-items: center;
      gap: 4px;
      background: rgba(255,255,255,0.08);
      border-radius: 99px;
      padding: 4px 6px;
      color: #fff;
    }
    .pm-lightbox-zoom button {
      background: transparent; border: 0; color: #fff; cursor: pointer;
      font-size: 20px; line-height: 1; width: 36px; height: 36px; border-radius: 50%;
    }
    .pm-lightbox-zoom button:hover { background: rgba(255,255,255,0.18); }
    .pm-lightbox-zoom span { font-size: 14px; min-width: 46px; text-align: center; }
    /* La foto se mueve y se acerca con transform: sin transición, para que
       seguir el dedo o la rueda no vaya con retraso. */
    #pm-lightbox img { will-change: transform; touch-action: none; }
    /* Pantalla pequeña: menos margen para la foto y la ✕ bien a mano. */
    @media (max-width: 640px) {
      #pm-lightbox { padding: 64px 10px 16px; }
      .pm-lightbox-close { top: 10px; right: 10px; }
      .pm-lightbox-zoom { top: 10px; left: 10px; }
    }

    #disp-ledger-table .badge-recarga {
      background: var(--positive-bg);
      color: var(--positive);
      padding: 3px 10px;
      border-radius: 99px;
      font-size: 0.72rem;
      font-weight: 600;
    }
    #disp-ledger-table .badge-debito {
      background: var(--negative-bg);
      color: var(--negative);
      padding: 3px 10px;
      border-radius: 99px;
      font-size: 0.72rem;
      font-weight: 600;
    }

    /* ═══════════════════════════════════════════════════════════════════
       LOGIN SCREEN (full overlay, oculto por defecto)
    ══════════════════════════════════════════════════════════════════════ */
    #login-screen {
      display: none;
      position: fixed; inset: 0;
      background: var(--rose-light);
      z-index: var(--capa-login);
      align-items: center;
      justify-content: center;
      padding: 24px;
    }
    #login-screen.show { display: flex; }
    .login-card {
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      box-shadow: var(--shadow-lg);
      padding: 32px 28px;
      width: 100%;
      max-width: 380px;
    }
    .login-brand {
      font-size: 22.4px;
      font-weight: 600;
      color: var(--text-dark);
      margin-bottom: 4px;
    }
    .login-brand span { color: var(--rose-med); }
    .login-sub {
      font-size: 0.78rem;
      color: var(--text-muted);
      letter-spacing: 0.08em;
      text-transform: uppercase;
      margin-bottom: 24px;
    }
    #login-form .form-group { margin-bottom: 14px; }
    #login-error {
      display: none;
      margin-top: 12px;
      padding: 8px 12px;
      background: var(--negative-bg);
      border: 1px solid color-mix(in srgb, var(--negative) 25%, transparent);
      color: var(--negative);
      border-radius: var(--radius-sm);
      font-size: 0.82rem;
    }
    #login-error.show { display: block; }
    /* Usuario bloqueado: no es "te equivocaste", es "hoy no entras y hay que
       avisarle al administrador". Se ve más y se lee de lejos. */
    #login-error.bloqueado {
      font-size: 0.92rem;
      font-weight: 600;
      padding: 12px 14px;
      line-height: 1.35;
    }

    /* Mientras no haya sesión, el resto de la app está oculto.
       Lo que vive DENTRO de #app se oculta solo; lo que vive fuera —las
       pantallas que se abren encima, y el visor de fotos— hay que nombrarlo
       aquí una por una. */
    body.unauthed #app,
    body.unauthed #edit-overlay,
    body.unauthed #destino-overlay,
    body.unauthed #auth-overlay,
    body.unauthed #history-overlay,
    body.unauthed #pm-lightbox,
    body.unauthed #persona-overlay { display: none !important; }
    body.unauthed #login-screen { display: flex; }

    /* ═══════════════════════════════════════════════════════════════════
       MAIN AREA
    ══════════════════════════════════════════════════════════════════════ */
    #app {
      flex: 1;
      display: flex;
      flex-direction: column;
      height: 100vh;
      overflow: hidden;
    }

    /* ── Botón principal "+ Registrar" ─────────────────────────────────
       Registrar es LA acción del día, así que va arriba del contenido,
       centrado y grande: es lo primero que se ve al entrar y no hay que
       buscarlo. Antes fue un flotante en la esquina inferior derecha;
       ahí tapaba la última fila de las tablas y obligaba a reservar
       espacio abajo en todas las vistas.

       Sólo se muestra en las secciones donde registrar tiene sentido
       (ver SECCIONES_CON_REGISTRAR en el JS de navegación). Vive dentro
       de #content, así que en la pantalla de login no aparece: body.unauthed
       ya oculta #app entero. */
    #registrar-bar {
      display: none;                  /* showSection decide cuándo se ve */
      justify-content: center;
      margin: 0 0 26px;
    }
    #registrar-bar.visible { display: flex; }

    #btn-registrar-main {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 12px;
      width: 100%;
      max-width: 400px;
      min-height: 64px;
      padding: 16px 32px;
      border: none;
      border-radius: var(--radius-md);
      background: var(--gold);
      color: #1d1608;                 /* texto oscuro sobre dorado sólido */
      font-family: var(--font-sans);
      font-size: 17.9px;
      font-weight: 700;
      letter-spacing: 0.01em;
      cursor: pointer;
      box-shadow: 0 4px 16px rgba(0,0,0,0.35);
      transition: background 0.14s ease, transform 0.14s ease, box-shadow 0.14s ease;
    }
    #btn-registrar-main .reg-plus {
      font-size: 29.6px;
      line-height: 1;
      font-weight: 400;
      margin-top: -3px;
    }
    #btn-registrar-main:hover {
      background: var(--gold-bright);
      transform: translateY(-1px);
      box-shadow: 0 8px 22px rgba(0,0,0,0.42);
    }
    #btn-registrar-main:active { transform: translateY(0) scale(0.99); }
    #btn-registrar-main:focus-visible {
      outline: 3px solid var(--gold-bright);
      outline-offset: 3px;
    }

    @media print {
      #registrar-bar { display: none !important; }
    }

    /* ── Aviso de servidor desactualizado (ver verificarVersionServidor) ─
       Barra fija arriba. No captura clics (pointer-events:none) y, cuando
       está visible, el layout completo baja para que no tape la barra
       superior ni sus botones. */
    #version-banner {
      position: fixed; left: 0; right: 0; top: 0; z-index: var(--capa-aviso);
      padding: 10px 16px;
      background: #7a2626; color: #fff;
      font-size: 0.9rem; font-weight: 600; text-align: center;
      box-shadow: 0 2px 10px rgba(0,0,0,.4);
      pointer-events: none;
    }
    /* El botón de recargar SÍ se puede tocar: la barra no captura clics,
       pero lo que lleva dentro tiene que poder pulsarse. */
    #version-banner button {
      pointer-events: auto; margin-left: 10px; cursor: pointer;
      background: #fff; color: #7a2626; border: 0; border-radius: 6px;
      padding: 6px 12px; font-size: 0.9rem; font-weight: 700;
    }
    /* Varios avisos del sistema a la vez (página vieja + mantenimiento): uno
       debajo del otro, los dos legibles. */
    #version-banner .vb-linea + .vb-linea {
      margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,.35);
    }
    /* MODO MANTENIMIENTO. Ámbar y no rojo: no es un error, es una puerta
       cerrada a propósito — y tiene que distinguirse de un aviso de fallo. */
    #version-banner.mantenimiento { background: #8a5a00; }
    #version-banner.mantenimiento button { color: #8a5a00; }

    /* ── CHAT: LA VENTANITA FLOTANTE (estilo Facebook) ────────────────
       Abajo a la derecha, pegada al borde. Plegada es una barrita de 44px;
       desplegada, una ventana de 340×430 — no media pantalla. Por encima de
       las secciones y por debajo del visor de fotos, del cartel del turno y
       del bloqueo: un mensaje no tapa un aviso que tranca la caja.

       No estorba los botones de la página: ocupa la esquina, y en pantalla
       pequeña se queda igual de baja (no cubre la barra de arriba ni el
       botón de registrar, que va centrado). */
    #chat-flotante {
      position: fixed; right: 16px; bottom: 0; z-index: var(--capa-chat);
      width: min(340px, calc(100vw - 24px));
      display: flex; flex-direction: column;
      font-size: 15px;
    }
    .chat-barra {
      display: flex; align-items: center; gap: 8px;
      width: 100%; padding: 11px 13px; cursor: pointer;
      background: var(--bg-card); color: var(--text-primary);
      border: 1px solid var(--border-soft); border-bottom: 0;
      border-radius: 10px 10px 0 0;
      box-shadow: 0 -4px 18px rgba(0,0,0,.35);
      font-family: inherit; font-size: 15px; text-align: left;
    }
    .chat-barra:hover { background: var(--bg-elevated) }
    /* Con mensajes sin leer, la barrita se pone dorada y late: es el aviso,
       y no tapa nada de lo que el operador esté haciendo. */
    .chat-barra.aviso { background: var(--gold); color: #1b1403; border-color: var(--gold) }
    .chat-barra.aviso .chat-barra-titulo { font-weight: 800 }
    .chat-barra.late { animation: chat-late 1.8s ease-in-out infinite }
    @keyframes chat-late { 0%,100% { filter: brightness(1) } 50% { filter: brightness(1.18) } }
    .chat-barra-titulo { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
    .chat-barra-num {
      min-width: 21px; height: 21px; padding: 0 5px; border-radius: 999px;
      background: #c0392b; color: #fff; font-size: 12.5px; font-weight: 800;
      line-height: 21px; text-align: center;
    }
    .chat-barra-flecha { color: var(--text-muted); font-size: 12px }
    /* [hidden] gana sobre el display:flex. Sin esto la ventanita seguía
       ocupando sus 430 px plegada: no se veía, pero su caja invisible
       quedaba en la esquina y se comía los clics de lo que hubiera debajo. */
    .chat-ventana[hidden], .chat-barra[hidden], .chat-interruptor[hidden] { display: none }
    .chat-ventana {
      display: flex; flex-direction: column;
      height: min(430px, 68vh);
      background: var(--bg-card);
      border: 1px solid var(--border-soft); border-bottom: 0;
      border-radius: 10px 10px 0 0;
      box-shadow: 0 -6px 26px rgba(0,0,0,.45);
      overflow: hidden;
    }
    .chat-cab {
      display: flex; align-items: center; gap: 6px;
      padding: 9px 10px 9px 13px; border-bottom: 1px solid var(--border-soft);
      background: var(--bg-elevated);
    }
    .chat-cab-titulo { font-weight: 800; font-size: 15.5px }
    .chat-cab-sub { font-size: 12.5px; color: var(--text-muted) }
    .chat-cab-btn {
      margin-left: auto; background: transparent; border: 0; color: var(--text-muted);
      font-size: 16px; cursor: pointer; line-height: 1; padding: 4px 6px;
    }
    .chat-cab-btn + .chat-cab-btn { margin-left: 0 }
    /* Con el silenciador escondido (operador), el que queda primero es el
       que tiene que empujar los botones a la derecha. */
    .chat-cab-btn[hidden] { display: none }
    .chat-cab-btn[hidden] + .chat-cab-btn { margin-left: auto }
    .chat-cab-btn:hover { color: var(--text-primary) }
    .chat-interruptor {
      padding: 9px 12px; border-bottom: 1px solid var(--border-soft);
      display: flex; flex-direction: column; gap: 7px; font-size: 14px;
    }
    .chat-cuerpo {
      flex: 1; overflow-y: auto; padding: 10px 12px;
      display: flex; flex-direction: column; gap: 7px;
    }
    .chat-pie { padding: 9px 12px 11px; border-top: 1px solid var(--border-soft) }
    .chat-msg {
      max-width: 86%; padding: 7px 10px; border-radius: 12px;
      font-size: 14.8px; line-height: 1.4; overflow-wrap: anywhere;
    }
    /* La imagen, de miniatura dentro de la burbuja. Alto tope para que una
       captura alargada no empuje el resto de la conversación fuera de la
       ventanita; se abre en grande en el visor de siempre. */
    .chat-img {
      display: block; max-width: 100%; max-height: 180px; width: auto;
      border-radius: 8px; margin-bottom: 5px; cursor: zoom-in;
      border: 1px solid var(--border-soft); object-fit: cover;
    }
    .chat-clip {
      flex: none; width: 34px; min-height: 38px; padding: 0;
      background: transparent; border: 1px solid var(--border-soft);
      border-radius: 8px; color: var(--text-muted); font-size: 16px; cursor: pointer;
    }
    .chat-clip:hover { color: var(--text-primary); background: var(--bg-elevated) }
    /* La imagen pegada espera aquí hasta que se pulsa Enviar: se puede quitar
       y se puede acompañar de texto. */
    .chat-adjunta {
      display: flex; align-items: center; gap: 7px;
      padding: 5px 6px; margin-bottom: 6px;
      border: 1px dashed var(--border-soft); border-radius: 8px;
    }
    .chat-adjunta[hidden] { display: none }
    .chat-adjunta img { width: 38px; height: 38px; object-fit: cover; border-radius: 5px; flex: none }
    .chat-msg.mio  { align-self: flex-end; background: rgba(201,169,97,.20); border: 1px solid rgba(201,169,97,.45) }
    .chat-msg.otro { align-self: flex-start; background: rgba(255,255,255,.07); border: 1px solid var(--border-soft) }
    .chat-msg-meta { font-size: 11px; color: var(--text-muted); margin-top: 2px }
    .chat-vacio { color: var(--text-muted); font-size: 14.5px; text-align: center; margin-top: 14px; line-height: 1.45 }
    .chat-sistema {
      align-self: center; font-size: 12.5px; color: var(--text-muted);
      text-align: center; padding: 3px 8px;
    }
    /* Pantalla pequeña: ocupa el ancho menos los márgenes, y más baja. */
    @media (max-width: 720px) {
      #chat-flotante { right: 8px; left: 8px; width: auto }
      .chat-ventana { height: min(62vh, 400px) }
    }
    body.con-version-banner #app {
      margin-top: var(--version-banner-h, 42px);
      height: calc(100vh - var(--version-banner-h, 42px));
    }

    /* ── CARTEL DEL TURNO ─────────────────────────────────────────────
       Trece minutos antes de que se le acabe la franja al operador, y diez
       antes del cierre de caja. Grande, amarillo y SIN botón de cerrar: no
       se puede ocultar ni minimizar, y no se va hasta que el turno quede
       cerrado. Esa es toda la intención — el cartel que se puede quitar es
       el cartel que se quita sin leerlo.

       Va fijo arriba, igual que el aviso de servidor viejo, y empuja la
       página hacia abajo para no tapar la barra ni sus botones. A
       diferencia de aquél, ÉSTE sí captura clics: lleva el botón que
       lleva directo a cerrar el turno. */
    #cartel-turno {
      position: fixed; left: 0; right: 0; top: 0; z-index: var(--capa-cartel-turno);
      display: none;
      padding: 14px 18px;
      background: #f6c945;
      color: #241c00;
      border-bottom: 3px solid #a8790b;
      box-shadow: 0 4px 18px rgba(0,0,0,.35);
      text-align: center;
      animation: cartel-turno-latido 2.4s ease-in-out infinite;
    }
    body.con-cartel-turno #cartel-turno { display: block }
    #cartel-turno .ct-titulo {
      font-size: 20px; font-weight: 800; letter-spacing: .01em;
      text-transform: uppercase; margin-bottom: 4px;
    }
    #cartel-turno .ct-texto {
      font-size: 17px; font-weight: 600; line-height: 1.35;
      max-width: 980px; margin: 0 auto;
    }
    #cartel-turno .ct-acciones { margin-top: 10px }
    #cartel-turno .ct-btn {
      display: inline-block; cursor: pointer;
      background: #241c00; color: #f6c945;
      border: 0; border-radius: 8px;
      padding: 9px 20px; font-size: 16px; font-weight: 700;
      font-family: inherit;
    }
    #cartel-turno .ct-btn:hover { background: #000 }
    /* Un cartel por cada cosa: si coinciden el fin de turno y el cierre de
       caja, se leen los dos, uno debajo del otro. */
    #cartel-turno .ct-uno + .ct-uno {
      margin-top: 10px; padding-top: 10px;
      border-top: 2px solid rgba(36,28,0,.25);
    }
    @keyframes cartel-turno-latido {
      0%, 100% { background: #f6c945 }
      50%      { background: #ffd96b }
    }
    /* Cuando también está el aviso de servidor viejo, el del turno se pone
       debajo: los dos se tienen que poder leer. */
    body.con-version-banner #cartel-turno { top: var(--version-banner-h, 42px) }
    body.con-cartel-turno #app { margin-top: var(--cartel-turno-h, 96px) }
    body.con-cartel-turno.con-version-banner #app {
      margin-top: calc(var(--version-banner-h, 42px) + var(--cartel-turno-h, 96px));
    }
    @media (max-width: 720px) {
      #cartel-turno { padding: 11px 12px }
      #cartel-turno .ct-titulo { font-size: 17px }
      #cartel-turno .ct-texto  { font-size: 15px }
    }

    /* ── CARTEL DEL COBRO QUE NO ENTRÓ EN WISPHUB ────────────────────
       El cobro se guarda y se responde ANTES de hablar con WispHub, así que
       el mostrador no puede esperar el resultado. Durante el 14-oct-2026 el
       resultado no se le decía NUNCA: la pantalla ponía "Mensualidad
       completa" mientras en WispHub la factura seguía abierta.

       Este cartel sale sólo cuando algo quedó mal, y por eso se puede leer:
       un aviso que sale en cada cobro se deja de mirar al tercero. Rojo,
       grande y arriba; se quita con su botón —nunca solo y nunca con un
       clic en cualquier parte—, porque el operador tiene que reconocer que
       lo leyó antes de que el cliente se vaya.

       ── Y TIENE DOS VOCES, DESDE EL 15-OCT-2026 ──────────────────────
       El rojo se gastó: salió sobre un cobro que había entrado perfecto en
       WispHub, porque la pantalla preguntaba a los 1,5 s y el trabajo real
       tardaba 5. Rich lo creyó, borró el cobro y volvió a cobrar.
       El rojo (sin clase) es para lo que FALLÓ, y sólo para eso. El
       `.cw-espera` es gris y sereno: "esto sigue en marcha". Un cobro
       tardando no es un cobro fallado, y la pantalla no puede confundirlos:
       es lo único que el operador tiene para decidir si deja ir al cliente. */
    #cartel-cobro-wh {
      position: fixed; left: 0; right: 0; top: 0; z-index: var(--capa-cartel-cobro);
      display: none;
      padding: 14px 18px;
      background: #7a2626; color: #fff;
      border-bottom: 3px solid #4a1414;
      box-shadow: 0 4px 18px rgba(0,0,0,.45);
      text-align: center;
    }
    body.con-cartel-cobro-wh #cartel-cobro-wh { display: block }
    #cartel-cobro-wh .cw-titulo {
      font-size: 19px; font-weight: 800; text-transform: uppercase; margin-bottom: 4px;
    }
    #cartel-cobro-wh .cw-texto {
      font-size: 16px; font-weight: 600; line-height: 1.35;
      max-width: 900px; margin: 0 auto;
    }
    #cartel-cobro-wh .cw-btn {
      margin-top: 10px; cursor: pointer;
      background: #fff; color: #7a2626; border: 0; border-radius: 8px;
      padding: 8px 20px; font-size: 15px; font-weight: 800; font-family: inherit;
    }
    /* La voz serena: nada rojo, nada en mayúsculas, sin botón que reconocer
       mientras el trabajo sigue — el cartel se quita solo en cuanto hay
       respuesta. Gris de la casa, no de alarma. */
    #cartel-cobro-wh.cw-espera {
      background: #31343c; color: #e8e8ea; border-bottom-color: #1d1f24;
      box-shadow: 0 4px 14px rgba(0,0,0,.3);
    }
    #cartel-cobro-wh.cw-espera .cw-titulo {
      text-transform: none; font-weight: 700; font-size: 17px; color: #fff;
    }
    #cartel-cobro-wh.cw-espera .cw-texto { font-weight: 500; color: #c9cace }
    #cartel-cobro-wh.cw-espera .cw-btn   { background: #e8e8ea; color: #31343c }
    /* Tres puntos que respiran, para que se vea que no está congelado. */
    #cartel-cobro-wh.cw-espera .cw-titulo::after {
      content: '…'; animation: cw-latido 1.4s ease-in-out infinite;
    }
    @keyframes cw-latido { 0%,100% { opacity: .25 } 50% { opacity: 1 } }
    /* Si coincide con los otros carteles, cada uno debajo del anterior: los
       tres se tienen que poder leer. */
    body.con-version-banner #cartel-cobro-wh { top: var(--version-banner-h, 42px) }
    body.con-cartel-turno #cartel-cobro-wh {
      top: calc(var(--cartel-turno-h, 96px));
    }
    body.con-cartel-turno.con-version-banner #cartel-cobro-wh {
      top: calc(var(--version-banner-h, 42px) + var(--cartel-turno-h, 96px));
    }
    /* Y empuja la página hacia abajo mientras está puesto, para no tapar la
       barra de arriba ni sus botones. La altura la mide el JS al enseñarlo,
       porque depende de cuánto texto traiga el aviso. */
    body.con-cartel-cobro-wh #app {
      margin-top: var(--cartel-cobro-wh-h, 150px);
      height: calc(100vh - var(--cartel-cobro-wh-h, 150px));
    }
    body.con-cartel-cobro-wh.con-version-banner #app {
      margin-top: calc(var(--version-banner-h, 42px) + var(--cartel-cobro-wh-h, 150px));
      height: calc(100vh - var(--version-banner-h, 42px) - var(--cartel-cobro-wh-h, 150px));
    }
    body.con-cartel-cobro-wh.con-cartel-turno #app {
      margin-top: calc(var(--cartel-turno-h, 96px) + var(--cartel-cobro-wh-h, 150px));
    }
    body.con-cartel-cobro-wh.con-cartel-turno.con-version-banner #app {
      margin-top: calc(var(--version-banner-h, 42px) + var(--cartel-turno-h, 96px)
                       + var(--cartel-cobro-wh-h, 150px));
    }
    @media (max-width: 720px) {
      #cartel-cobro-wh { padding: 11px 12px }
      #cartel-cobro-wh .cw-titulo { font-size: 16px }
      #cartel-cobro-wh .cw-texto  { font-size: 14px }
    }

    /* ── Búsqueda global ─────────────────────────────────────────────
       Vive en el encabezado y está siempre a la vista: encontrar un pago
       no debería obligar a acordarse primero de en qué categoría estaba.
       Los resultados caen debajo, encima de todo, sin sacar a nadie de
       la pantalla en la que está trabajando. */
    #bg-wrap {
      position: relative;
      flex: 0 1 340px;
      min-width: 150px;
    }
    #bg-input {
      width: 100%;
      padding: 8px 32px 8px 34px;
      border-radius: 99px;
      border: 1px solid var(--border);
      background: var(--white);
      font-family: var(--font-sans);
      font-size: 0.85rem;
      color: var(--text-dark);
      /* El anillo de foco lo pone la regla única del final. */
      transition: border-color .18s, box-shadow .18s;
    }
    #bg-input:focus {
      border-color: var(--gold);
      box-shadow: 0 0 0 3px rgba(191,155,74,0.14);
    }
    #bg-input::placeholder { color: var(--text-muted); }
    #bg-icon {
      position: absolute; left: 12px; top: 50%;
      transform: translateY(-50%);
      width: 14px; height: 14px;
      pointer-events: none;
      color: var(--text-muted);
    }
    #bg-clear {
      position: absolute; right: 8px; top: 50%;
      transform: translateY(-50%);
      border: none; background: none; cursor: pointer;
      color: var(--text-muted); font-size: 16px; line-height: 1;
      padding: 4px; display: none;
    }
    #bg-wrap.has-text #bg-clear { display: block; }
    #bg-panel {
      position: absolute;
      top: calc(100% + 8px); right: 0;
      width: min(560px, 92vw);
      max-height: min(70vh, 560px);
      overflow-y: auto;
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      box-shadow: var(--shadow-lg);
      z-index: var(--capa-panel);
      display: none;
    }
    #bg-panel.open { display: block; }
    .bg-head {
      padding: 9px 14px;
      font-size: 0.72rem;
      text-transform: uppercase;
      letter-spacing: .05em;
      color: var(--text-muted);
      border-bottom: 1px solid var(--border-soft);
      position: sticky; top: 0;
      background: var(--white);
    }
    .bg-row {
      display: block; width: 100%;
      text-align: left;
      padding: 10px 14px;
      border: none; background: none; cursor: pointer;
      border-bottom: 1px solid var(--border-soft);
      transition: background .12s;
    }
    .bg-row:hover, .bg-row:focus { background: var(--rose-light); }
    .bg-row-top {
      display: flex; justify-content: space-between;
      align-items: baseline; gap: 10px;
    }
    .bg-row-cliente {
      font-weight: 600; font-size: 0.9rem; color: var(--text-dark);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .bg-row-monto {
      font-family: var(--font-serif);
      font-size: 16px; white-space: nowrap; color: var(--text-dark);
    }
    .bg-row-sub {
      display: flex; flex-wrap: wrap; gap: 6px;
      font-size: 0.74rem; color: var(--text-muted); margin-top: 2px;
    }
    .bg-row-sub span:not(:last-child)::after { content: ' ·'; }
    .bg-tag {
      display: inline-block;
      font-size: 0.66rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: .04em;
      padding: 1px 6px; border-radius: 4px;
      background: var(--rose-light); color: var(--text-muted);
    }
    /* Una transacción anulada se sigue encontrando —puede que se busque
       justo para comprobar que lo está— pero no se puede confundir con
       una viva. */
    .bg-row.anulada .bg-row-cliente,
    .bg-row.anulada .bg-row-monto { text-decoration: line-through; opacity: .6; }
    .bg-tag.anulada { background: rgba(198,64,64,.12); color: var(--negative); }
    .bg-vacio, .bg-cargando {
      padding: 22px 14px; text-align: center;
      font-size: 0.85rem; color: var(--text-muted);
    }
    .bg-pie {
      padding: 8px 14px; font-size: 0.72rem;
      color: var(--text-muted); text-align: center;
      border-top: 1px solid var(--border-soft);
    }
    @media (max-width: 860px) {
      #bg-wrap { flex: 1 1 auto; min-width: 0; }
      #bg-panel { width: min(560px, 96vw); }
    }

    /* Nota: el botón "+ Registrar" del encabezado se eliminó; la única
       forma de registrar es el botón grande de arriba del contenido
       (#btn-registrar-main). */

    /* ── Content ────────────────────────────────────────────────────── */

    .section { display: none; }
    .section.active { display: block; }

    /* ═══════════════════════════════════════════════════════════════════
       COMPONENTES REUTILIZABLES
    ══════════════════════════════════════════════════════════════════════ */

    /* Título de sección */
    .section-title {
      font-family: var(--font-sans);
      font-size: 27.2px;
      font-weight: 600;
      color: var(--text-dark);
      margin-bottom: 4px;
    }
    .section-sub {
      font-size: 0.82rem;
      color: var(--text-muted);
      margin-bottom: 24px;
    }

    /* Divider dorado */
    .gold-line {
      height: 2px;
      background: linear-gradient(90deg, var(--gold), transparent);
      margin: 0 0 24px;
      border-radius: 99px;
      width: 80px;
    }

    /* ── KPI Cards ──────────────────────────────────────────────────── */
    .kpi-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
      gap: 16px;
      margin-bottom: 28px;
    }
    .kpi-card {
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 20px 22px;
      box-shadow: var(--shadow);
      position: relative;
      overflow: hidden;
      transition: transform 0.18s, box-shadow 0.18s;
    }
    .kpi-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
    .kpi-card::before {
      content: '';
      position: absolute;
      top: 0; left: 0; right: 0;
      height: 3px;
    }
    .kpi-card.gold::before   { background: linear-gradient(90deg, var(--gold), var(--gold-light)); }
    .kpi-card.rose::before   { background: linear-gradient(90deg, var(--rose-deep), var(--rose-med)); }
    .kpi-card.teal::before   { background: linear-gradient(90deg, #6bbfb5, #9dddd6); }

    .kpi-icon {
      width: 40px; height: 40px;
      border-radius: 10px;
      display: flex; align-items: center; justify-content: center;
      font-size: 18.4px;
      margin-bottom: 14px;
    }
    .kpi-card.gold   .kpi-icon { background: rgba(201,169,110,0.15); color: var(--gold-dark); }
    .kpi-card.rose   .kpi-icon { background: rgba(232,160,176,0.15); color: var(--rose-med); }
    .kpi-card.teal   .kpi-icon { background: rgba(107,191,181,0.15); color: #27a89a; }

    .kpi-label {
      font-size: 0.75rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      font-weight: 500;
      margin-bottom: 6px;
    }
    .kpi-value {
      font-family: var(--font-sans);
      font-size: 26px;
      font-weight: 800;
      color: #3d2535;
      line-height: 1;
      margin-bottom: 6px;
    }

    /* ── Card genérica ──────────────────────────────────────────────── */
    .card {
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      box-shadow: var(--shadow);
      overflow: hidden;
      margin-bottom: 20px;
    }
    .card-header {
      padding: 16px 20px;
      border-bottom: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
    .card-title {
      font-family: var(--font-sans);
      font-size: 17.6px;
      font-weight: 600;
      color: var(--text-dark);
    }
    .card-body { padding: 20px; }

    /* ── Tabla ──────────────────────────────────────────────────────── */
    .table-wrap { overflow-x: auto; }
    table { width: 100%; border-collapse: collapse; font-size: 0.87rem; }
    thead tr { background: var(--rose-light); }
    th {
      padding: 11px 14px;
      text-align: left;
      font-size: 0.72rem;
      font-weight: 600;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      border-bottom: 1px solid var(--border);
      white-space: nowrap;
    }
    td {
      padding: 12px 14px;
      border-bottom: 1px solid rgba(240,213,220,0.5);
      color: var(--text-dark);
      vertical-align: middle;
    }
    tbody tr:last-child td { border-bottom: none; }
    tbody tr:hover { background: var(--rose-light); }

    /* Badge */
    .badge {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 3px 10px;
      border-radius: 99px;
      font-size: 0.73rem;
      font-weight: 600;
      letter-spacing: 0.02em;
    }
    .badge-green  { background: var(--positive-bg); color: var(--positive); }

    /* ── Botones ────────────────────────────────────────────────────── */
    .btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 9px 20px;
      border-radius: 99px;
      border: none;
      cursor: pointer;
      font-family: var(--font-sans);
      font-size: 0.85rem;
      font-weight: 500;
      transition: all 0.18s;
    }
    .btn-primary   { background: var(--text-dark); color: var(--white); }
    .btn-primary:hover { background: #5c3a4a; }
    .btn-gold      { background: var(--gold); color: var(--text-dark); }
    .btn-gold:hover { background: var(--gold-dark); color: var(--white); }
    .btn-outline   { background: transparent; color: var(--text-dark); border: 1px solid var(--border); }
    .btn-outline:hover { background: var(--rose-light); }
    .btn-danger    { background: transparent; color: var(--negative); border: 1px solid color-mix(in srgb, var(--negative) 30%, transparent); }
    .btn-danger:hover { background: var(--negative-bg); }
    .btn-sm { padding: 6px 14px; font-size: 0.8rem; }
    .btn-icon { width: 32px; height: 32px; padding: 0; justify-content: center; border-radius: 8px; }
    /* Botón de guardar/registrar/confirmar deshabilitado hasta que todos los
       campos obligatorios estén completos (regla global de UX). Se ve
       claramente inactivo y no responde al click. */
    .btn:disabled, .btn[disabled], .btn.is-disabled {
      opacity: 0.4;
      cursor: not-allowed;
      filter: grayscale(0.5);
      box-shadow: none;
    }

    .btn-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

    /* ── Formularios ────────────────────────────────────────────────── */
    .form-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 16px;
    }
    .form-group { display: flex; flex-direction: column; gap: 6px; }
    .form-group.span2 { grid-column: span 2; }
    .form-group.full { grid-column: 1 / -1; }
    /* Asterisco dorado en campos obligatorios */
    .form-group label .req { color: var(--gold); margin-left: 2px; font-weight: 700; }
    /* Validación visual en vivo (modal Nuevo cliente internet y otros) */
    .form-error {
      display: none;
      font-size: 0.75rem;
      color: var(--negative);
      margin-top: 2px;
      line-height: 1.3;
    }
    .form-group.error > input,
    .form-group.error > select,
    .form-group.error > textarea {
      border-color: var(--negative) !important;
      box-shadow: 0 0 0 3px rgba(225, 60, 60, 0.12) !important;
      background: #fff5f5;
    }
    .form-group.error .form-error { display: block; }
    label {
      font-size: 0.78rem;
      font-weight: 500;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.06em;
    }
    input, select, textarea {
      background: var(--rose-light);
      border: 1px solid var(--border);
      border-radius: var(--radius-sm);
      color: var(--text-dark);
      padding: 10px 14px;
      font-family: var(--font-sans);
      font-size: 0.9rem;
      width: 100%;
      transition: border-color 0.18s, box-shadow 0.18s;
    }
    input:focus, select:focus, textarea:focus {
      /* El anillo de foco lo pone la regla única del final. */
      border-color: var(--gold);
      box-shadow: 0 0 0 3px rgba(201,169,110,0.15);
      background: var(--white);
    }
    textarea { resize: vertical; min-height: 80px; }

    /* Alert */
    .alert {
      padding: 10px 16px;
      border-radius: var(--radius-sm);
      font-size: 0.85rem;
      margin-bottom: 16px;
    }
    .alert-success { background: var(--positive-bg); border: 1px solid color-mix(in srgb, var(--positive) 30%, transparent); color: var(--positive); }
    .alert-error   { background: var(--negative-bg); border: 1px solid color-mix(in srgb, var(--negative) 25%, transparent); color: var(--negative); }

    /* Empty state */
    .empty {
      padding: 48px 20px;
      text-align: center;
      color: var(--text-muted);
      font-size: 0.88rem;
    }
    .empty-icon { font-size: 40px; margin-bottom: 12px; opacity: 0.4; }

    /* ═══════════════════════════════════════════════════════════════════
       GRÁFICAS
    ══════════════════════════════════════════════════════════════════════ */
    .chart-container {
      position: relative;
      height: 280px;
      padding: 4px;
    }

    /* ── La hoja de Gráficas ────────────────────────────────────────
       Mismo papel que el resto de la libreta: nada de cuadros de otro
       sistema. Los colores salen todos de variables, así que el tema
       claro y el oscuro se pintan solos. */
    /* ── Los tres pasos ─────────────────────────────────────────────
       Numerados y en fila de arriba abajo: quien los usa no lee
       instrucciones, sigue los números. */
    .inf-paso {
      border: 1px solid var(--linea); border-radius: 14px;
      background: var(--n2); margin-bottom: 14px; overflow: hidden;
    }
    .inf-paso-cab {
      display: flex; align-items: center; gap: 13px;
      padding: 13px 18px; border-bottom: 1px solid var(--linea);
      background: var(--glow-suave);
    }
    .inf-paso-n {
      flex: 0 0 auto; width: 29px; height: 29px; border-radius: 50%;
      display: flex; align-items: center; justify-content: center;
      background: var(--oro); color: #141001;
      font-family: var(--font-sans); font-size: 15px; font-weight: bold;
    }
    [data-tema="claro"] .inf-paso-n { background: var(--oro-claro); color: var(--text-on-gold); }
    .inf-paso-tit { font-family: var(--font-serif); font-size: 18px; font-weight: 700; color: var(--texto); }
    .inf-paso-sub { font-size: 13px; color: var(--gris-2); font-style: italic; margin-top: 1px; }
    .inf-paso-cuerpo { padding: 16px 18px; }
    /* El paso 3 se distingue: es el que hace algo. */
    .inf-paso-generar .inf-paso-cab { background: transparent; }
    .inf-paso-generar .inf-paso-cuerpo { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
    .inf-paso-generar .btn { font-size: 16px; padding: 14px 40px; }

    /* Paso 1 — las casillas de categoría */
    .inf-chk {
      display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
      padding: 8px 14px; border-radius: 10px; border: 1px solid var(--linea);
      font-size: 15px; color: var(--texto); transition: all .18s;
      /* Son nombres de categoría, no rótulos de campo: la regla global de
         <label> los ponía en versalitas y a 12px, y catorce nombres en
         mayúscula gritan y se leen peor. */
      text-transform: none; letter-spacing: 0;
    }
    .inf-chk:hover { border-color: var(--oro-med); background: var(--glow-suave); }
    .inf-chk input { width: auto; margin: 0; accent-color: var(--oro); }
    .inf-chk-todo { margin-bottom: 12px; font-weight: 700; }
    .inf-chk-todo.activo { border-color: var(--oro-med); background: var(--glow-suave); color: var(--oro); }
    .inf-cats { display: flex; flex-wrap: wrap; gap: 8px; transition: opacity .18s; }
    /* Con "Todo el negocio" puesto la lista sigue a la vista —para que se
       entienda qué hay— pero apagada: no está eligiendo nada. */
    .inf-cats.apagado { opacity: .45; }

    /* Paso 2 — los cuatro modos, excluyentes */
    .inf-modos { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
    .inf-modo {
      font-family: var(--font-sans); font-size: 15px; cursor: pointer;
      padding: 9px 22px; border-radius: 999px;
      border: 1px solid var(--oro-dim); background: transparent; color: var(--gris);
      transition: all .18s;
    }
    .inf-modo:hover { color: var(--oro); border-color: var(--oro-med); }
    /* El activo se ve encendido y los otros tres apagados: de un vistazo se
       sabe cuál manda, que es justo lo que un grupo de casillas no deja ver. */
    .inf-modo.activo {
      background: var(--oro); border-color: var(--oro); color: #141001; font-weight: bold;
    }
    /* Ver la nota de contraste del tema claro, más abajo. */
    [data-tema="claro"] .inf-modo.activo {
      background: var(--oro-claro); border-color: var(--oro-claro); color: var(--text-on-gold);
    }
    .inf-campos { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; }
    /* Sin esto, los cuatro periodos se ven a la vez: el display:flex de
       arriba le gana al [hidden]{display:none} del navegador, y el JS puede
       poner hidden=true todo lo que quiera que el campo sigue en pantalla. */
    .inf-campos[hidden] { display: none; }
    .inf-nota { font-size: 13px; color: var(--gris-2); font-style: italic; align-self: center; }
    .gf-campo { display: flex; flex-direction: column; gap: 4px; }
    .gf-campo label { font-size: 12px; letter-spacing: 1px; color: var(--gris); text-transform: uppercase; }
    .gf-campo input { width: 185px; }

    /* El aviso de que el periodo no cuadra, pegado al botón que no funcionó. */
    .inf-error {
      color: var(--rojo); font-size: 14.5px; font-weight: 700; line-height: 1.45;
    }

    /* Encabezado del resultado: qué se generó, y los botones de llevárselo. */
    .inf-cabecera {
      display: flex; justify-content: space-between; align-items: flex-start;
      gap: 14px; flex-wrap: wrap;
      margin: 26px 2px 18px; padding-top: 18px; border-top: 2px solid var(--oro-dim);
    }
    .inf-cabecera-tit {
      font-family: var(--font-serif); font-size: 22px; font-weight: 700; color: var(--oro);
    }
    .gf-leyenda-rango { font-size: 14px; color: var(--text-muted); font-style: italic; }
    .gf-exportar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
    /* Por qué los tres botones están apagados. Va a su lado, no en un aviso
       aparte: la pregunta nace mirándolos. */
    .gf-sin-datos {
      font-size: 14px;
      color: var(--text-muted);
      font-style: italic;
    }
    .gf-exportar .btn[disabled] { opacity: .5; cursor: not-allowed; }

    /* La fila del total cierra la tabla del informe: se busca antes que
       ninguna otra, así que se lee más fuerte y con una línea de oro. */
    .gf-tabla tfoot .gf-total td {
      border-top: 2px solid var(--oro-dim); border-bottom: none;
      font-weight: 700; color: var(--oro); background: var(--glow-suave);
    }

    /* Franja de totales del rango. Es lo primero que se lee. */
    .gf-kpis {
      display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
      gap: 12px; margin-bottom: 20px;
    }
    .gf-kpi {
      border: 1px solid var(--linea); border-radius: 12px; padding: 13px 16px;
      background: var(--n2);
    }
    .gf-kpi-label {
      font-size: 12px; letter-spacing: 1px; text-transform: uppercase;
      color: var(--gris); margin-bottom: 5px;
    }
    .gf-kpi-val { font-size: 22px; font-weight: 700; color: var(--texto); line-height: 1.15; }
    .gf-kpi-val.oro { color: var(--oro) }
    .gf-kpi-val.verde { color: var(--verde) }
    .gf-kpi-val.rojo { color: var(--rojo) }
    .gf-kpi-sub { font-size: 13px; color: var(--gris-2); margin-top: 3px; }

    /* Cada gráfico y su tabla de cifras viven en la misma tarjeta. */
    .gf-card {
      border: 1px solid var(--linea); border-radius: 14px;
      background: var(--n2); margin-bottom: 20px; overflow: hidden;
    }
    .gf-card-head {
      padding: 14px 18px; border-bottom: 1px solid var(--linea);
      display: flex; justify-content: space-between; align-items: baseline; gap: 14px; flex-wrap: wrap;
    }
    .gf-card-title { font-family: var(--font-serif); font-size: 19px; color: var(--texto); font-weight: 700; }
    .gf-card-nota { font-size: 13px; color: var(--gris-2); font-style: italic; }
    .gf-card-body { padding: 16px 18px; }
    .gf-chart { position: relative; height: 260px; }
    .gf-chart.alto { height: 320px; }

    /* Cifras al lado del gráfico. */
    .gf-cifras { display: flex; flex-wrap: wrap; gap: 10px 26px; margin-top: 14px;
                 padding-top: 13px; border-top: 1px solid var(--linea); }
    .gf-cifra-label { font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: var(--gris) }
    .gf-cifra-val { font-size: 17px; font-weight: 700; color: var(--texto) }

    .gf-tabla { width: 100%; border-collapse: collapse; font-size: 15px }
    .gf-tabla th {
      text-align: left; padding: 9px 12px; font-size: 12px; letter-spacing: 1px;
      text-transform: uppercase; color: var(--gris); border-bottom: 1px solid var(--linea);
      font-weight: 700; white-space: nowrap;
    }
    .gf-tabla td { padding: 9px 12px; border-bottom: 1px solid var(--linea); color: var(--texto) }
    .gf-tabla tr:last-child td { border-bottom: none }
    .gf-tabla .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap }
    .gf-tabla .cat { font-weight: 700 }
    .gf-tabla tbody tr:hover td { background: var(--glow-suave) }
    .gf-tabla .prod td { font-size: 14px; color: var(--gris); padding-left: 28px }
    .gf-tabla .prod td:first-child::before { content: '· '; color: var(--oro-dim) }

    .gf-vacio {
      padding: 26px 18px; text-align: center; color: var(--gris);
      font-style: italic; font-size: 15px;
    }
    @media (max-width: 700px) {
      .inf-campos { flex-direction: column; align-items: stretch }
      .gf-campo input { width: 100% }
      .inf-modo { flex: 1 1 44%; }
      .gf-chart { height: 220px }
    }

    /* ── Categorías creadas desde la app (panel Precios) ─────────────── */
    .pcat-hint {
      font-size: 0.76rem;
      color: var(--text-muted);
      margin-top: 4px;
      line-height: 1.35;
    }
    .pcat-iconos {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
      gap: 8px;
      margin-top: 6px;
    }
    .pcat-icono-btn {
      background: var(--bg-card);
      border: 1px solid var(--border-soft);
      border-radius: 10px;
      padding: 10px 4px 6px;
      cursor: pointer;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 4px;
      font-family: inherit;
    }
    .pcat-icono-btn svg {
      width: 26px; height: 26px; display: block;
      stroke: var(--gold-bright); color: var(--gold-bright);
    }
    .pcat-icono-btn span {
      font-size: 0.62rem;
      color: var(--text-muted);
      text-align: center;
      line-height: 1.15;
    }
    .pcat-icono-btn.selected {
      border-color: var(--gold);
      box-shadow: 0 0 0 1px var(--gold);
    }
    /* Ya lo usa otra categoría: se avisa, no se prohíbe. */
    .pcat-icono-btn.en-uso { opacity: 0.72; }
    .pcat-icono-btn.en-uso svg { stroke: var(--text-muted); color: var(--text-muted); }
    .pcat-icono-btn.selected.en-uso { opacity: 1; }
    .pcat-icono-btn.selected.en-uso svg { stroke: var(--gold-bright); color: var(--gold-bright); }
    .pcat-icono-uso {
      font-size: 0.56rem;
      font-style: normal;
      text-transform: uppercase;
      letter-spacing: .04em;
      color: var(--warning);
      line-height: 1;
    }
    .pcat-iconos {
      max-height: 260px;
      overflow-y: auto;
    }
    .pcat-monedas { display: flex; gap: 8px; margin-top: 4px; }
    .pcat-moneda-btn.selected {
      border-color: var(--gold);
      box-shadow: 0 0 0 1px var(--gold);
    }
    .precios-cat-icono svg {
      width: 22px; height: 22px; display: block;
      stroke: var(--gold-bright); color: var(--gold-bright);
    }
    .precios-badge {
      font-size: 0.66rem;
      text-transform: uppercase;
      letter-spacing: .04em;
      border: 1px solid var(--border-gold);
      color: var(--gold-dark);
      border-radius: 999px;
      padding: 2px 8px;
      margin-left: 6px;
      white-space: nowrap;
    }
    .precios-group-title {
      font-size: 0.78rem;
      text-transform: uppercase;
      letter-spacing: .06em;
      color: var(--text-muted);
      margin: 18px 0 8px;
    }

    /* ═══════════════════════════════════════════════════════════════════
       MODAL DE REGISTRO
    ══════════════════════════════════════════════════════════════════════ */
    #edit-overlay,
    #destino-overlay,
    #auth-overlay,
    #history-overlay,
    #persona-overlay,
    #psub-overlay,
    #pcat-overlay,
    #inv-carga-overlay,
    #inv-ajuste-overlay,
    #ci-overlay,
    #spl-abono-overlay,
    #spl-edit-overlay,
    #disp-edit-overlay,
    #ver-detail-overlay,
    #nomina-modal-overlay,
    #usuarios-modal-overlay,
    #recibo-overlay,
    #bg-detalle-overlay,
    #pend-overlay,
    #cierre-manual-overlay{
      position: fixed; inset: 0;
      background: rgba(61,37,53,0.45);
      backdrop-filter: blur(4px);
      z-index: var(--capa-modal);
      display: none;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    #auth-overlay    { z-index: var(--capa-modal-clave); }
    #history-overlay { z-index: var(--capa-modal-hist); }
    /* ci-overlay se abre desde el flujo de registrar, que ahora vive en la
       hoja: se queda por encima del resto de modales de esa pantalla. */
    #ci-overlay      { z-index: var(--capa-modal-ci); }
    #edit-overlay.open,
    #destino-overlay.open,
    #auth-overlay.open,
    #history-overlay.open,
    #persona-overlay.open,
    #psub-overlay.open,
    #pcat-overlay.open,
    #inv-carga-overlay.open,
    #inv-ajuste-overlay.open,
    #ci-overlay.open,
    #spl-abono-overlay.open,
    #spl-edit-overlay.open,
    #disp-edit-overlay.open,
    #ver-detail-overlay.open,
    #nomina-modal-overlay.open,
    #usuarios-modal-overlay.open,
    #recibo-overlay.open,
    #bg-detalle-overlay.open,
    #pend-overlay.open,
    #cierre-manual-overlay.open{ display: flex; }
    /* Pendientes de pago: se abre también desde Inicio y desde Historial. */
    #pend-overlay { z-index: var(--capa-modal-pend); }
    .modal {
      background: var(--white);
      border-radius: var(--radius);
      box-shadow: var(--shadow-lg);
      width: 100%;
      max-width: 560px;
      max-height: 90vh;
      overflow-y: auto;
      animation: modal-in 0.25s;
    }
    @keyframes modal-in {
      from { transform: scale(0.95) translateY(10px); opacity: 0; }
      to   { transform: scale(1) translateY(0); opacity: 1; }
    }
    .modal-header {
      padding: 20px 24px 16px;
      border-bottom: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
    .modal-title {
      font-family: var(--font-sans);
      font-size: 20.8px;
      font-weight: 600;
      color: var(--text-dark);
    }
    .modal-close {
      width: 32px; height: 32px;
      border-radius: 50%;
      border: none;
      background: var(--rose-light);
      color: var(--text-muted);
      cursor: pointer;
      font-size: 16px;
      display: flex; align-items: center; justify-content: center;
      transition: background 0.18s;
    }
    .modal-close:hover { background: var(--rose-mid); color: var(--text-dark); }
    .modal-body  { padding: 20px 24px; }
    .modal-footer {
      padding: 16px 24px;
      border-top: 1px solid var(--border);
      display: flex;
      gap: 10px;
      justify-content: flex-end;
    }

    /* ═══════════════════════════════════════════════════════════════════
       MODAL DE CAPTURA MANUAL (Día 2)
    ══════════════════════════════════════════════════════════════════════ */
    .cap-step-hint {
      font-size: 0.85rem;
      color: var(--text-muted);
      margin-bottom: 16px;
    }
    .cap-tipos-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
      gap: 12px;
    }
    .cap-tipo-card {
      background: var(--rose-light);
      border: 1px solid var(--border);
      border-radius: var(--radius-md);
      padding: 16px 14px;
      cursor: pointer;
      transition: all 0.15s;
      display: flex;
      flex-direction: column;
      gap: 6px;
      min-height: 76px;
      text-align: left;
      font-family: inherit;
      color: var(--text-dark);
      width: 100%;
    }
    .cap-tipo-card:hover {
      border-color: var(--gold);
      transform: translateY(-2px);
      box-shadow: 0 4px 14px rgba(201,169,97,0.15);
    }
    .cap-tipo-card .cap-tipo-icon {
      font-size: 22.4px;
      color: var(--gold-dark);
      line-height: 1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-height: 26px;
    }
    .cap-tipo-card .cap-tipo-icon svg {
      width: 26px;
      height: 26px;
      display: block;
      stroke: var(--gold-bright);
      color: var(--gold-bright);
    }
    .cap-tipo-card .cap-tipo-name {
      font-weight: 600;
      font-size: 0.92rem;
    }
    .cap-tipo-card .cap-tipo-sub {
      font-size: 0.74rem;
      color: var(--text-muted);
    }

    .cap-back {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 16px;
      padding-bottom: 12px;
      border-bottom: 1px solid var(--border);
    }
    .cap-current-tipo {
      font-weight: 600;
      color: var(--text-dark);
      font-size: 0.95rem;
    }

    #cap-form .form-grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 14px;
    }
    #cap-form .form-group { display: flex; flex-direction: column; gap: 5px; }
    #cap-form .form-group.full { grid-column: 1 / -1; }
    #cap-form .form-group label {
      font-size: 0.78rem;
      color: var(--text-muted);
      font-weight: 500;
    }
    #cap-form .form-group label .req { color: var(--negative); margin-left: 2px; }
    #cap-form input,
    #cap-form select,
    #cap-form textarea {
      width: 100%;
      padding: 9px 12px;
      border: 1px solid var(--border-soft);
      border-radius: 8px;
      font-size: 0.92rem;
      font-family: inherit;
      background: var(--bg-input);
      color: var(--text-primary);
      min-height: 40px;
      transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
    }
    #cap-form textarea { resize: vertical; min-height: 60px; }
    #cap-form input::placeholder,
    #cap-form textarea::placeholder { color: var(--text-dim); }
    #cap-form input:focus,
    #cap-form select:focus,
    #cap-form textarea:focus {
      /* El anillo de foco lo pone la regla única del final. */
      border-color: var(--gold);
      box-shadow: 0 0 0 3px rgba(201,169,97,0.18);
      background: var(--bg-elevated);
    }
    #cap-form select option { background: var(--bg-card); color: var(--text-primary); }

    /* File picker: input nativo OCULTO + <label> visible que actúa como
       botón. Esto evita el bug del input[type=file] estilizado que en
       algunos casos quedaba con el ::file-selector-button no clickable
       (efecto colateral de display:flex + overflow:hidden + padding:0
       sobre el control nativo, agravado por overlays del modal). El
       patrón label[for] es bulletproof: clic en label dispara input.click()
       internamente, sin depender del render del pseudo-elemento. */
    #section-registrar input[type="file"].cap-photo-input {
      position: absolute;
      width: 1px;
      height: 1px;
      opacity: 0;
      overflow: hidden;
      clip: rect(0 0 0 0);
      clip-path: inset(50%);
      white-space: nowrap;
      border: 0;
      padding: 0;
      margin: -1px;
      pointer-events: none;
    }
    .cap-photo-picker {
      display: flex;
      align-items: center;
      gap: 10px;
      flex-wrap: wrap;
      min-height: 48px;
      padding: 8px 12px;
      border: 1px dashed var(--border-soft);
      border-radius: 10px;
      background: var(--bg-input);
      transition: border-color 0.15s, background 0.15s;
    }
    .cap-photo-picker:hover {
      border-color: var(--border-gold);
      background: var(--bg-elevated);
    }
    .cap-photo-picker.has-file {
      border-style: solid;
      border-color: var(--border-gold);
    }
    .cap-photo-btn {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 10px 16px;
      background: var(--bg-gold-grad);
      color: var(--gold-bright);
      border: 1px solid var(--border-soft);
      border-radius: 8px;
      font-family: inherit;
      font-weight: 600;
      font-size: 0.82rem;
      cursor: pointer;
      transition: background 0.15s, color 0.15s;
      user-select: none;
      line-height: 1;
    }
    .cap-photo-btn:hover {
      background: linear-gradient(135deg, #3a2c12 0%, #4d3a14 100%);
      color: #fff;
    }
    .cap-photo-btn:focus-within,
    .cap-photo-input.cap-photo-input:focus + .cap-photo-btn {
      outline: 2px solid var(--gold);
      outline-offset: 2px;
    }
    .cap-photo-btn svg {
      width: 16px;
      height: 16px;
      stroke: currentColor;
      fill: none;
    }
    .cap-photo-filename {
      font-size: 0.82rem;
      color: var(--text-muted);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      max-width: 248px;
    }
    .cap-photo-picker.has-file .cap-photo-filename {
      color: var(--positive);
    }
    /* "Quitar foto": a la vista, pero sin competir con el botón de la
       cámara. Sólo aparece cuando hay una foto puesta. */
    .cap-photo-quitar {
      background: transparent;
      border: 1px solid var(--border-soft);
      color: var(--text-muted);
      border-radius: 8px;
      padding: 7px 12px;
      font-family: inherit;
      font-size: 0.82rem;
      line-height: 1;
      cursor: pointer;
    }
    .cap-photo-quitar:hover { color: var(--negative); border-color: var(--negative); }
    .cap-photo-quitar[hidden] { display: none; }

    /* Botón "← Volver" del paso 2 — más prominente que el viejo
       "‹ Cambiar tipo" para que el operador NO crea que la única
       salida es la X (que cierra todo el modal). */
    .cap-back-btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 8px 14px;
      background: transparent;
      border: 1px solid var(--border);
      border-radius: 8px;
      color: var(--text-muted);
      font-family: inherit;
      font-size: 0.88rem;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.15s;
    }
    .cap-back-btn:hover {
      border-color: var(--gold);
      color: var(--gold-bright);
      background: rgba(201,169,97,0.06);
    }
    .cap-back-btn svg {
      width: 16px;
      height: 16px;
      stroke: currentColor;
      fill: none;
    }

    /* Bloque de foto + IA */
    .cap-photo-input {
      font-size: 0.85rem;
      min-height: 44px;
    }
    .cap-photo-preview {
      display: none;
      max-width: 240px;
      max-height: 160px;
      border-radius: 8px;
      object-fit: cover;
      border: 1px solid var(--border);
    }
    .cap-photo-preview.show { display: block; }
    .cap-photo-status {
      font-size: 0.78rem;
      color: var(--text-muted);
      min-height: 1.1em;
    }
    .cap-photo-status.ok    { color: var(--positive); }
    .cap-photo-status.error { color: var(--negative); }

    /* Discrepancia (servicios oro) */
    .cap-discrep {
      font-size: 0.82rem;
      padding: 8px 12px;
      border-radius: 8px;
      margin-top: 6px;
      font-weight: 500;
    }
    .cap-discrep.ok {
      background: rgba(90, 181, 116, 0.12);
      color: var(--positive);
      border: 1px solid rgba(90, 181, 116, 0.3);
    }
    .cap-discrep.bad {
      background: rgba(217, 116, 116, 0.12);
      color: var(--negative);
      border: 1px solid rgba(217, 116, 116, 0.3);
    }

    /* Autocomplete cliente */
    .cap-ac { position: relative; }
    .cap-ac-list {
      position: absolute;
      top: 100%; left: 0; right: 0;
      background: var(--bg-card);
      border: 1px solid var(--border-soft);
      border-radius: 8px;
      box-shadow: 0 8px 32px rgba(0,0,0,0.5);
      max-height: 220px;
      overflow-y: auto;
      z-index: 20;
      display: none;
    }
    .cap-ac-list.open { display: block; }
    /* La lista abierta con la flecha enseña TODOS los clientes, así que tiene
       que poder recorrerse: alto de unas siete filas y scroll propio. El
       `overscroll-behavior: contain` es lo que evita que, al llegar al final
       con la rueda o con el dedo, el empujón siga y arrastre el modal de
       detrás — en tablet eso se siente como que la pantalla se va sola. */
    .cap-ac-list {
      max-height: 320px;
      overscroll-behavior: contain;
      -webkit-overflow-scrolling: touch;
    }
    /* La flecha vive dentro del campo, pegada a la derecha. Va en su propio
       envoltorio y no en `.cap-ac` a secas, porque debajo del campo puede
       haber más cosas (la nota de "créalo primero en Clientes de internet")
       y entonces "pegado abajo" no sería el borde del campo. */
    .cap-ac-campo { position: relative; }
    .cap-ac-campo > input[type="text"] { padding-right: 44px; width: 100%; }
    .cap-ac-toggle {
      position: absolute;
      right: 1px; top: 50%; transform: translateY(-50%);
      width: 40px; height: calc(100% - 2px);
      /* El campo mide 40 px y el dedo necesita 44: la flecha se los toma
         centrada, asomando un par de píxeles por arriba y por abajo. Como no
         tiene fondo propio, eso no se ve — sólo se nota al tocarla, que es
         de lo que se trata. */
      min-height: 44px;
      display: flex; align-items: center; justify-content: center;
      background: none; border: 0; padding: 0;
      cursor: pointer; color: var(--text-muted);
      border-radius: 0 8px 8px 0;
    }
    /* El realce sólo donde hay ratón: en táctil pintaría un rectángulo más
       alto que el campo. */
    @media (hover: hover) {
      .cap-ac-toggle:hover { color: var(--gold-bright); background: var(--bg-elevated); }
    }
    .cap-ac-toggle svg { width: 18px; height: 18px; transition: transform .15s ease; }
    .cap-ac-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
    /* El dedo necesita blanco al que apuntar: en táctil la flecha se ensancha. */
    @media (hover: none) and (pointer: coarse) {
      .cap-ac-toggle { width: 48px; }
      .cap-ac-campo > input[type="text"] { padding-right: 56px; }
    }
    .cap-ac-item {
      padding: 9px 12px;
      cursor: pointer;
      font-size: 0.88rem;
      color: var(--text-primary);
      border-bottom: 1px solid var(--border-subtle);
    }
    .cap-ac-item:last-child { border-bottom: none; }
    .cap-ac-item:hover, .cap-ac-item.active { background: var(--bg-elevated); }
    .cap-ac-item .cap-ac-sub {
      font-size: 0.74rem;
      color: var(--text-muted);
      margin-top: 2px;
    }
    .cap-ac-item.create { color: var(--gold-bright); font-weight: 600; }

    /* Spinner pequeño dentro del modal */
    .cap-mini-spinner {
      display: inline-block;
      width: 12px; height: 12px;
      border: 2px solid var(--border);
      border-top-color: var(--gold);
      border-radius: 50%;
      animation: spin 0.7s linear infinite;
      vertical-align: -2px;
      margin-right: 6px;
    }

    /* Grupos del paso 1 (LADO A / LADO B / Otros) */
    .cap-tipos-section { margin-bottom: 22px; }
    .cap-tipos-section-title {
      font-size: 0.72rem;
      font-weight: 600;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      margin-bottom: 10px;
    }

    /* Sub-pasos del paso 2 */
    .cap-substep {
      border: 1px solid var(--border);
      border-radius: 10px;
      padding: 14px;
      margin-bottom: 14px;
      background: var(--white);
    }
    .cap-substep.done {
      background: rgba(90, 181, 116, 0.04);
      border-color: rgba(90, 181, 116, 0.3);
    }
    .cap-substep-title {
      display: flex;
      align-items: center;
      gap: 8px;
      font-weight: 600;
      font-size: 0.92rem;
      color: var(--text-dark);
      margin-bottom: 12px;
    }
    /* ── Transiciones del modal de registro ───────────────────────────
       El formulario se re-arma ENTERO en cada elección (tipo de envío,
       subcategoría, medio de pago, volver atrás). Sin transición eso se ve
       como un parpadeo: desaparece una cosa y aparece otra de golpe.

       Cómo se anima sin hacer esperar al operador: el DOM real se reemplaza
       de forma SÍNCRONA —quien llama sigue encontrando los campos en el
       acto— y lo que se anima es un FANTASMA, una copia del contenido
       saliente superpuesta y sin capturar clics, que se desvanece por
       encima mientras el nuevo contenido entra por debajo. Nadie espera a
       que termine ninguna animación.

       Sólo transform y opacity: nada que provoque reflow. */
    #cap-body, #cap-form { position: relative; }

    .cap-ghost {
      position: absolute;
      top: 0; left: 0; right: 0;
      z-index: 3;
      pointer-events: none;   /* no se puede pulsar lo que ya no existe */
      animation: cap-sale 0.19s cubic-bezier(0.2, 0.85, 0.4, 1) both;
    }
    @keyframes cap-sale {
      from { opacity: 1; transform: translate3d(0, 0, 0); }
      to   { opacity: 0; transform: translate3d(0, -8px, 0); }
    }
    /* El fantasma es una FOTO de lo que había, no una escena que se vuelve a
       reproducir. La copia se toma del HTML tal cual está, y ese HTML todavía
       lleva las clases de entrada del repintado anterior: dentro del fantasma
       esas animaciones arrancan otra vez desde cero, así que el contenido que
       se va APARECE encima del que entra y luego se desvanece. Eso era el
       parpadeo de superposición. El JS quita esas marcas al copiar; esta regla
       lo garantiza aunque algo se escape (un fantasma anidado, una animación
       de un widget). */
    .cap-ghost * { animation: none !important; transition: none !important; }
    /* El botón que el operador acaba de elegir NO se desvanece con los
       demás: se va volando a su nueva posición como título, así que en el
       fantasma se oculta para que no se vea dos veces. */
    .cap-ghost .cap-elegido-fantasma { opacity: 0; }

    /* Entrada retrasada 80 ms: el saliente y el entrante NO pueden ser
       legibles a la vez. Antes se cruzaban —el que salía aún al 65 % cuando el
       que entraba ya iba por el 85 %— y dos capas legibles superpuestas se
       leen como un defecto, no como una transición. Ahora el saliente cae
       rápido y el entrante empieza cuando ya casi no está. */
    .cap-entra {
      animation: cap-entra 0.26s cubic-bezier(0.22, 0.8, 0.3, 1) both;
      animation-delay: 80ms;
    }
    @keyframes cap-entra {
      from { opacity: 0; transform: translate3d(0, 12px, 0); }
      to   { opacity: 1; transform: translate3d(0, 0, 0); }
    }

    /* El título que sustituye al botón elegido arranca donde estaba el
       botón y con parte de su tamaño, y viaja hasta su sitio: se ve cómo
       uno se convierte en el otro. El desplazamiento y la escala los
       calcula el JS al vuelo (no se pueden saber de antemano) y los pasa
       por estas variables. */
    .cap-morph { animation: cap-morph 0.32s cubic-bezier(0.22, 0.8, 0.3, 1) both; }
    @keyframes cap-morph {
      from {
        opacity: 0.5;
        transform: translate3d(var(--mx, 0px), var(--my, 0px), 0) scale(var(--ms, 1));
      }
      to { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
    }

    /* Nada de esto es información: si se pide menos movimiento, el cambio
       de paso es instantáneo y ya. */
    @media (prefers-reduced-motion: reduce) {
      .cap-ghost { display: none !important; }
      .cap-entra, .cap-morph { animation: none !important; }
    }

    /* Tipo de envío ya elegido: deja de ser un botón y pasa a ser el
       encabezado del formulario. Sin borde ni fondo de tarjeta a propósito
       — si siguiera pareciendo un botón, el operador volvería a pulsarlo. */
    .cap-pmtipo-elegido {
      display: flex;
      align-items: baseline;
      flex-wrap: wrap;
      gap: 4px 12px;
      margin-bottom: 16px;
      padding-bottom: 12px;
      border-bottom: 2px solid rgba(255, 209, 0, 0.55);
    }
    .cap-pmtipo-titulo {
      font-size: 19.5px;
      font-weight: 700;
      letter-spacing: 0.08em;
      color: var(--gold);
      line-height: 1.15;
    }
    .cap-pmtipo-sub {
      font-size: 0.8rem;
      color: var(--text-muted);
      flex: 1;
    }
    /* Discreto y a un lado: es una salida por si se equivocó, no una acción
       que haya que ofrecerle con el mismo peso que el formulario. */
    .cap-pmtipo-cambiar {
      background: none;
      border: none;
      padding: 2px 4px;
      font-family: inherit;
      font-size: 0.8rem;
      color: var(--text-muted);
      text-decoration: underline;
      cursor: pointer;
    }
    .cap-pmtipo-cambiar:hover { color: var(--cyan-accent); }

    .cap-substep-num {
      width: 22px; height: 22px;
      border-radius: 50%;
      background: var(--gold);
      color: #1a1208;
      font-size: 0.74rem;
      font-weight: 700;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
    }
    .cap-substep.done .cap-substep-num { background: var(--positive); color: #fff; }

    /* Componente VisionConfirmation */
    .cap-vc {
      background: linear-gradient(135deg, rgba(201,169,97,0.08), rgba(201,169,97,0.03));
      border: 1px solid var(--border-gold);
      border-radius: 10px;
      padding: 14px;
      margin-top: 10px;
    }
    .cap-vc-title {
      font-size: 0.82rem;
      font-weight: 600;
      color: var(--text-dark);
      margin-bottom: 10px;
    }
    .cap-vc-data {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 4px 12px;
      font-size: 0.88rem;
      margin-bottom: 12px;
    }
    .cap-vc-key { color: var(--text-muted); }
    .cap-vc-val { color: var(--text-dark); font-weight: 600; }
    .cap-vc-val.null { color: var(--text-muted); font-weight: 400; font-style: italic; }
    .cap-vc-actions { display: flex; gap: 8px; flex-wrap: wrap; }
    .cap-vc-counter {
      font-size: 0.76rem;
      color: var(--text-muted);
      margin-left: auto;
      align-self: center;
    }
    .cap-vc-counter.warn { color: var(--warning); font-weight: 600; }

    /* ── Los datos del comprobante, en líneas ──────────────────────────
       Cinco líneas pegadas a la izquierda, una por dato, todas del mismo
       tamaño. Antes eran cinco campos abiertos en dos columnas con título y
       párrafo: ocupaba media pantalla y el operador tenía que desplazarse
       para llegar al botón de guardar. Un dato que ya está bien no necesita
       una casilla abierta — necesita verse y poder tocarse. */
    .cap-cl { margin-top: 8px; display: flex; flex-direction: column; gap: 1px }
    .cap-cl-linea {
      display: flex; align-items: center; gap: 7px;
      padding: 3px 6px; border-radius: 6px; cursor: pointer;
      font-size: 0.9rem; line-height: 1.5; text-align: left;
      background: transparent; border: 0; width: 100%; font-family: inherit;
    }
    .cap-cl-linea:hover { background: rgba(255,255,255,.05) }
    /* La línea que leyó la IA no invita a tocarse: ni cursor de mano ni
       realce al pasar por encima. */
    .cap-cl-linea.fija { cursor: default }
    .cap-cl-linea.fija:hover { background: transparent }
    .cap-cl-k { color: var(--text-muted); min-width: 74px }
    /* Lo que leyó la IA va en verde. Vacío o escrito a mano se distingue sin
       gritar: el verde dice "esto lo puso la foto", no "esto está bien". */
    .cap-cl-v { color: var(--verde); font-weight: 600; flex: 1; min-width: 0 }
    .cap-cl-v.manual { color: var(--text-dark); font-weight: 600 }
    .cap-cl-v.vacio  { color: var(--text-muted); font-weight: 400; font-style: italic }
    .cap-cl-chip {
      font-size: 0.64rem; letter-spacing: .6px; text-transform: uppercase;
      padding: 1px 5px; border-radius: 999px; border: 1px solid currentColor;
      opacity: .55; flex: none;
    }
    .cap-cl-chip.ia     { color: var(--verde) }
    .cap-cl-chip.manual { color: var(--text-muted) }
    .cap-cl-lapiz { color: var(--text-muted); opacity: .45; font-size: .78rem; flex: none }
    .cap-cl-linea:hover .cap-cl-lapiz { opacity: .9 }
    /* En edición la línea no se mueve de sitio: la casilla ocupa el hueco
       del valor y nada salta. */
    /* [hidden] no gana sobre display:flex: sin esto, la casilla cerrada
       seguía ocupando sus 30 px en cada línea — invisible, pero el bloque
       pesaba casi lo mismo que el recuadro que vino a sustituir. */
    .cap-cl-edit[hidden] { display: none }
    .cap-cl-edit { flex: 1; min-width: 0; display: flex; gap: 6px; align-items: center }
    .cap-cl-edit input { width: 100%; min-height: 30px; padding: 2px 7px; font-size: 0.9rem }
    @media (max-width: 520px) {
      .cap-cl-k { min-width: 64px; font-size: 0.86rem }
      .cap-cl-linea { font-size: 0.86rem }
    }

    /* Panel "Promedio del oro" (sólo Pago Móvil — vive bajo la zona de
       carga de comprobante en el modal de captura). Bs/g calculado en
       vivo desde amount_bs / gramos. */
    .cap-promedio-oro {
      margin-top: 12px;
      padding: 10px 14px;
      background: rgba(201,169,97,0.10);
      border: 1px solid var(--border-gold);
      border-left-width: 3px;
      border-radius: 8px;
      display: flex;
      align-items: baseline;
      gap: 10px;
      flex-wrap: wrap;
    }
    .cap-promedio-oro-label {
      font-size: 0.82rem;
      color: var(--text-muted);
      font-weight: 600;
    }
    .cap-promedio-oro-value {
      font-family: var(--font-sans);
      color: var(--gold-bright);
      font-weight: 700;
      font-size: 18.4px;
      letter-spacing: 0.01em;
      font-variant-numeric: tabular-nums;
    }

    /* Indicador de confianza de Vision (báscula) */
    .cap-conf-badge {
      display: inline-block;
      font-size: 0.66rem;
      font-weight: 700;
      letter-spacing: 0.04em;
      padding: 2px 8px;
      border-radius: 999px;
      margin-left: 6px;
      vertical-align: middle;
      text-transform: uppercase;
    }
    .cap-conf-badge.baja  { background: #c0392b; color: #fff; }

    /* Estado bloqueado (campos llenados por Vision) */
    .cap-locked-label::after {
      content: ' 🔒';
      font-size: 0.74rem;
      color: var(--positive);
    }
    .cap-locked-label.override::after {
      content: ' ✏ (manual)';
      font-size: 0.7rem;
      color: var(--warning);
      font-style: italic;
    }

    /* Medio de pago selector */
    .cap-medio-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 10px;
    }
    .cap-medio-btn {
      position: relative;
      padding: 16px 10px 14px;
      border: 1px solid var(--border-soft);
      border-radius: 12px;
      background: var(--bg-card);
      cursor: pointer;
      font-size: 0.85rem;
      font-weight: 500;
      color: var(--text-secondary);
      text-align: center;
      transition: border-color 0.18s, background 0.18s, color 0.18s, transform 0.15s, box-shadow 0.18s;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 8px;
      min-height: 92px;
    }
    .cap-medio-btn .cap-medio-icon {
      width: 28px;
      height: 28px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      color: var(--gold-dim);
      transition: color 0.18s, transform 0.18s;
    }
    .cap-medio-btn .cap-medio-icon svg { width: 100%; height: 100%; display: block; }
    .cap-medio-btn .cap-medio-label {
      font-size: 0.84rem;
      line-height: 1.2;
      letter-spacing: 0.01em;
    }
    .cap-medio-btn:hover {
      border-color: var(--gold);
      background: var(--bg-elevated);
      color: var(--text-primary);
      transform: translateY(-1px);
      box-shadow: 0 6px 18px rgba(201,169,97,0.18);
    }
    .cap-medio-btn:hover .cap-medio-icon { color: var(--gold); }
    .cap-medio-btn.selected {
      background: var(--bg-gold-grad);
      color: var(--gold-bright);
      border-color: var(--gold);
      font-weight: 700;
      box-shadow: 0 0 0 1px var(--gold), 0 8px 28px rgba(201,169,97,0.28);
    }
    .cap-medio-btn.selected .cap-medio-icon {
      color: var(--gold-bright);
      transform: scale(1.08);
    }
    @media (max-width: 540px) {
      .cap-medio-grid { grid-template-columns: 1fr; }
      .cap-medio-btn { min-height: 72px; flex-direction: row; gap: 12px; padding: 12px 14px; }
      .cap-medio-btn .cap-medio-icon { width: 24px; height: 24px; }
    }

    /* ═══════════════════════════════════════════════════════════════════
       RESPONSIVE
    ══════════════════════════════════════════════════════════════════════ */
    /* Tablet — columnas más angostas, tarjetas más chicas */
    @media (max-width: 1024px) and (min-width: 769px) {
      #content { padding: 22px; }
      .kpi-grid { grid-template-columns: repeat(2, 1fr); }
    }

    /* Móvil — una sola columna */
    @media (max-width: 768px) {
      #topbar-title { font-size: 16.8px; }
      #topbar-date { display: none; }

      #content { padding: 14px; }

      /* Registrar en móvil: ocupa todo el ancho disponible (el max-width
         de 400px sigue mandando en pantallas medianas). */
      #registrar-bar { margin-bottom: 20px; }
      #btn-registrar-main {
        max-width: none;
        min-height: 60px;
        padding: 16px 24px;
        font-size: 17px;
      }
      #btn-registrar-main .reg-plus { font-size: 27.2px; }

      .kpi-grid     { grid-template-columns: 1fr; }
      .disp-persona-grid,
      .cap-tipos-grid{ grid-template-columns: 1fr; }
      .form-grid    { grid-template-columns: 1fr; }
      .form-group.span2 { grid-column: span 1; }
      #cap-form .form-grid { grid-template-columns: 1fr; }

      /* Botones touch-friendly */
      .btn, button.btn, .nav-item,
      .cap-tipo-card, .cap-ac-item{ min-height: 44px; }

      /* Modales — casi pantalla completa */
      #edit-overlay, #destino-overlay, #auth-overlay,
      #history-overlay, #persona-overlay {
        padding: 8px;
      }
      .modal {
        width: 95vw;
        max-width: 95vw;
        max-height: 95vh;
      }
      .modal-body { padding: 16px; }
      .modal-header { padding: 14px 16px 12px; }
      .modal-footer { padding: 12px 16px; }

      /* Tablas grandes con scroll horizontal */
      .table-wrap, .pm-table-wrap,
      .cu-table-wrap{
        -webkit-overflow-scrolling: touch;
        overflow-x: auto;
      }
      table { font-size: 0.8rem; }

    }

    @media (max-width: 420px) {
      .kpi-grid { grid-template-columns: 1fr; }
    }

    /* ── Panel de respaldos ────────────────────────────────────────
       Va ARRIBA del todo en Configuración general y a propósito: es lo
       único de esta pantalla que, si falla, se lleva el negocio entero.
       En el camino feliz no pide nada — dice cuándo fue el último y ya. */
    .resp-panel {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius);
      padding: 18px;
      margin-top: 16px;
    }
    /* Sin respaldo o con más de 48 h: el borde entero se pone rojo. Un
       respaldo que falla en silencio es igual a no tener respaldo, así que
       esto no puede parecer un detalle más de la lista. */
    .resp-panel.alerta { border-color: rgba(217,116,116,0.55); }

    .resp-encabezado {
      display: flex; align-items: center; justify-content: space-between;
      gap: 12px; flex-wrap: wrap; margin-bottom: 14px;
    }
    .resp-titulo { font-size: 0.98rem; font-weight: 700; color: var(--text-primary); }
    .resp-sub { font-size: 0.8rem; color: var(--text-muted); margin-top: 2px; }

    .resp-banner {
      display: flex; align-items: flex-start; gap: 10px;
      padding: 12px 14px; border-radius: var(--radius-sm);
      background: var(--negative-bg);
      border: 1px solid rgba(217,116,116,0.35);
      color: var(--negative);
      font-size: 0.86rem; line-height: 1.45;
      margin-bottom: 14px;
    }
    .resp-banner-icono { font-size: 17.6px; line-height: 1.2; }

    .resp-estado {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
      gap: 12px;
      margin-bottom: 14px;
    }
    .resp-dato {
      background: var(--bg-input);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-sm);
      padding: 10px 12px;
      min-width: 0;
    }
    .resp-dato-label {
      font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.07em;
      color: var(--text-muted); margin-bottom: 4px;
    }
    .resp-dato-valor {
      font-size: 0.92rem; font-weight: 600; color: var(--text-primary);
      overflow-wrap: anywhere;
    }
    .resp-dato-valor.ok   { color: var(--positive); }
    .resp-dato-valor.mal  { color: var(--negative); }

    .resp-lista { margin-top: 6px; }
    .resp-lista-titulo {
      font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.07em;
      color: var(--text-muted); margin: 16px 0 8px;
    }
    .resp-fila {
      display: flex; align-items: center; gap: 10px;
      padding: 7px 0;
      border-bottom: 1px solid var(--border-subtle);
      font-size: 0.83rem;
    }
    .resp-fila:last-child { border-bottom: none; }
    .resp-fila-nombre { flex: 1; min-width: 0; overflow-wrap: anywhere; font-family: ui-monospace, monospace; font-size: 0.78rem; }
    .resp-fila-peso { color: var(--text-muted); white-space: nowrap; }
    .resp-fila-tag {
      font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em;
      padding: 2px 6px; border-radius: 4px; white-space: nowrap;
    }
    .resp-fila-tag.ok  { background: rgba(90,181,116,0.15); color: var(--positive); }
    .resp-fila-tag.mal { background: rgba(217,116,116,0.15); color: var(--negative); }
    .resp-error-txt { color: var(--negative); font-size: 0.78rem; overflow-wrap: anywhere; }

    /* Listas plegadas: a la vista sólo la más reciente. La lista entera
       estiraba el panel hasta dejar el resto de Configuración fuera de
       pantalla. Lo de dentro son exactamente las mismas filas. */
    .resp-vermas {
      background: none; border: none; cursor: pointer;
      padding: 8px 0 2px; margin: 0;
      font: inherit; font-size: 0.8rem;
      color: var(--gold); text-align: left;
    }
    .resp-vermas:hover { text-decoration: underline; }
    .resp-plegado[hidden] { display: none; }

    /* ── Purga de datos antiguos ────────────────────────────────────
       Vive en Configuración general, debajo del respaldo y a propósito:
       lo primero que se ve encima es la copia de seguridad. El panel va
       con borde rojo permanente —no como aviso puntual— porque lo que
       hace no se deshace. */
    .purga-panel { border-color: rgba(217,116,116,0.38); }
    .purga-paso {
      margin-top: 18px; padding-top: 14px;
      border-top: 1px solid var(--border-subtle);
    }
    .purga-paso:first-of-type { border-top: none; padding-top: 0; }
    .purga-campos {
      display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
      margin-top: 10px;
    }
    .purga-campo { display: flex; flex-direction: column; gap: 5px; min-width: 160px; }
    .purga-campo label {
      font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.07em;
      color: var(--text-muted);
    }
    /* Las dos listas del "antes": qué se va y qué se queda, una al lado de
       la otra. Puestas juntas no hace falta creerle a nadie: se leen. */
    .purga-listas {
      display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
      gap: 12px; margin-top: 12px;
    }
    .purga-lista {
      background: var(--bg-input);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-sm);
      padding: 12px 14px;
    }
    .purga-lista.borra    { border-color: rgba(217,116,116,0.42); }
    .purga-lista.conserva { border-color: rgba(90,181,116,0.38); }
    .purga-lista-tit {
      font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.07em;
      margin-bottom: 7px; font-weight: 700;
    }
    .purga-lista.borra    .purga-lista-tit { color: var(--negative); }
    .purga-lista.conserva .purga-lista-tit { color: var(--positive); }
    .purga-lista ul {
      margin: 0; padding-left: 17px;
      font-size: 0.81rem; line-height: 1.5; color: var(--text-secondary);
    }
    .purga-lista li { margin-bottom: 3px; }
    .purga-frase {
      font-family: ui-monospace, monospace; font-weight: 700;
      color: var(--negative); letter-spacing: 0.04em;
    }

    /* ── Los tres cuadros que se leen de lejos ──────────────────────────
       "Fotos leídas por la IA", "Cuentas USDT" y "Borrar datos antiguos"
       no se rellenan como un formulario: se consultan, muchas veces de
       pie y de un vistazo. Van dos puntos por encima del resto de la app
       — la misma letra y los mismos colores de La Libreta, sólo más
       grandes. Las medidas van todas juntas aquí, con el id del panel
       delante: las clases son compartidas, y sin el id esto le subiría la
       letra al panel de respaldos y a media app de paso. */
    #vision-uso-panel .card-title,
    #cuentas-usdt-panel .card-title  { font-size: 20px; }
    #vision-uso-panel table,
    #vision-uso-panel td             { font-size: 16px; }
    #vision-uso-panel th             { font-size: 13px; }
    #vision-uso-panel .pm-history-link { font-size: 0.89rem; }

    #cuentas-usdt-panel .cfg-card-title { font-size: 1.06rem; }
    #cuentas-usdt-panel .cfg-card-desc  { font-size: 0.93rem; }
    #cuentas-usdt-panel .ci-empty       { font-size: 1.11rem; }
    #cuentas-usdt-panel .badge          { font-size: 13px; }

    #purga-panel .resp-titulo        { font-size: 1.09rem; }
    #purga-panel .resp-sub           { font-size: 0.91rem; }
    #purga-panel .resp-dato-label    { font-size: 0.81rem; }
    #purga-panel .resp-dato-valor    { font-size: 1.03rem; }
    #purga-panel .resp-lista-titulo  { font-size: 0.89rem; }
    #purga-panel .resp-error-txt     { font-size: 0.89rem; }
    #purga-panel .purga-campo label  { font-size: 0.81rem; }
    #purga-panel .purga-lista-tit    { font-size: 0.83rem; }
    #purga-panel .purga-lista ul     { font-size: 0.92rem; }
    #purga-panel input,
    #purga-panel select              { font-size: 16px; }

    /* Los botones, después de lo demás: .btn-sm tiene que ganarle a .btn
       en los elementos que llevan las dos clases. */
    #purga-panel .btn                { font-size: 15px; }
    #vision-uso-panel .btn-sm,
    #cuentas-usdt-panel .btn-sm,
    #purga-panel .btn-sm             { font-size: 14px; }

    /* ── Mi Nómina — la pantalla del operador ───────────────────────────
       Es donde alguien mira cuánto va a cobrar y por qué le descuentan.
       Se lee de pie, con prisa y a veces desde el teléfono, así que va un
       punto por encima del resto de la app y lo que más importa —la cifra
       y el motivo de cada multa— es lo más grande de su bloque. Los
       colores y las formas son los de La Libreta: mismas tarjetas, mismo
       oro, misma serif en cursiva para los nombres. */
    .mn-card .card-header {
      display: flex; align-items: center; justify-content: space-between;
      gap: 12px; flex-wrap: wrap;
    }
    /* El rótulo que deja claro que aquí no se toca nada. */
    .mn-solo-lectura {
      font-size: 0.78rem; color: var(--text-muted);
      border: 1px solid var(--border-subtle); border-radius: 999px;
      padding: 2px 12px; letter-spacing: 0.06em; text-transform: uppercase;
      white-space: nowrap;
    }
    .mn-encabezado { margin-bottom: 16px; }
    .mn-nombre {
      font-family: var(--font-serif); font-style: italic;
      font-size: 1.35rem; font-weight: bold; color: var(--text-primary);
    }
    .mn-cargo { font-size: 0.95rem; color: var(--text-muted); font-style: italic; margin-top: 2px; }

    /* La cifra: lo primero y lo más grande de la pantalla. */
    .mn-cobro {
      text-align: center; padding: 20px 14px; margin-bottom: 18px;
      border: 1px solid var(--border-subtle); border-radius: 14px;
      background: var(--bg-input);
    }
    .mn-cobro-rotulo {
      font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.12em;
      color: var(--text-muted);
    }
    .mn-cobro-cifra { font-size: 2.4rem; line-height: 1.1; margin: 8px 0 2px; font-weight: bold; }
    .mn-cobro-sub { font-size: 1rem; color: var(--text-secondary); font-style: italic; }

    /* La cuenta, escrita como se escribiría en un papel: el salario arriba,
       las restas debajo y la raya antes del total. Es la respuesta a "¿por
       qué cobro esto?" sin que haya que hacer ninguna cuenta de cabeza. */
    .mn-cuenta {
      border: 1px solid var(--border-subtle); border-radius: 12px;
      padding: 6px 16px; margin-bottom: 18px;
    }
    .mn-cuenta-fila {
      display: flex; align-items: baseline; justify-content: space-between;
      gap: 16px; padding: 9px 0; font-size: 1rem; color: var(--text-secondary);
    }
    .mn-cuenta-fila + .mn-cuenta-fila { border-top: 1px solid var(--border-subtle); }
    .mn-cuenta-monto { font-weight: 600; color: var(--text-primary); white-space: nowrap; }
    .mn-cuenta-fila.resta .mn-cuenta-monto { color: var(--negative); }
    .mn-cuenta-fila.total {
      border-top: 2px solid var(--border-subtle);
      font-size: 1.1rem; font-weight: 700; color: var(--text-primary);
    }
    .mn-cuenta-fila.total .mn-cuenta-monto { font-size: 1.15rem; }

    .mn-datos {
      display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px;
    }
    .mn-dato {
      background: var(--bg-input); border: 1px solid var(--border-subtle);
      border-radius: 10px; padding: 12px 14px; min-width: 0;
    }
    .mn-dato-rotulo {
      font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em;
      color: var(--text-muted); margin-bottom: 4px;
    }
    .mn-dato-valor { font-size: 1.05rem; font-weight: 600; color: var(--text-primary); overflow-wrap: anywhere; }

    /* Las multas. El motivo va grande y arriba: es la respuesta a la única
       pregunta que se hace quien ve un descuento en su pago. */
    .mn-multas-total { font-size: 1.05rem; font-weight: 700; color: var(--negative); white-space: nowrap; }
    .mn-multas-nota { font-size: 0.9rem; color: var(--text-muted); line-height: 1.5; margin-bottom: 12px; }
    .mn-multa {
      position: relative; margin-bottom: 10px; padding: 12px 140px 12px 14px;
      border: 1px solid var(--border-subtle); border-left: 3px solid var(--negative);
      border-radius: 10px;
    }
    .mn-multa-motivo { font-size: 1.05rem; color: var(--text-primary); line-height: 1.4; }
    .mn-multa-pie {
      font-size: 0.85rem; color: var(--text-muted); margin-top: 5px;
      display: flex; gap: 14px; flex-wrap: wrap;
    }
    .mn-multa-monto {
      position: absolute; right: 14px; top: 12px;
      font-size: 1.15rem; font-weight: 700; color: var(--negative); white-space: nowrap;
    }
    .mn-sin-multas { font-size: 1rem; color: var(--text-muted); }

    /* Las solicitudes de adelanto que hizo él. No son descuentos —todavía no
       son nada— así que NO se pintan de rojo como una multa: la que espera va
       en el ámbar de "falta algo por pasar", la aprobada en verde y la negada
       en gris. El color es la primera respuesta: en qué quedó lo que pidió. */
    .mn-sol {
      margin-top: 10px; padding: 11px 14px; border-radius: 10px;
      border: 1px solid var(--border-subtle); border-left: 3px solid var(--text-muted);
    }
    .mn-sol.pendiente { border-left-color: var(--warning); }
    .mn-sol.aprobada  { border-left-color: var(--positive); }
    .mn-sol-titulo { font-size: 1rem; color: var(--text-primary); line-height: 1.4; }
    .mn-sol-pie    { font-size: 0.85rem; color: var(--text-muted); margin-top: 4px; line-height: 1.5; }
    .mn-sol-sep {
      margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--border-subtle);
    }
    .mn-sol-sep-titulo {
      font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em;
      color: var(--text-muted);
    }

    /* ── Lo que ya cobraste, mes por mes ──────────────────────────────
       Era una lista corrida. Al año son cincuenta y pico de renglones que
       nadie termina de leer; plegada por mes son doce, y el que quiere
       saber cuánto cobró en agosto lo tiene escrito en el renglón sin
       abrir nada. */
    .mn-mes { border-top: 1px solid var(--border-subtle); }
    .mn-mes:first-child { border-top: none; }

    /* El renglón es un BOTÓN de verdad: en la tablet se toca con el dedo y
       con el teclado se llega con el tabulador. 56px de alto es el piso por
       debajo del cual un dedo empieza a fallar, y el área que se puede
       tocar es el renglón entero, no la flechita. */
    .mn-mes-cab {
      width: 100%; min-height: 56px; display: flex; align-items: center; gap: 12px;
      padding: 12px 18px; background: none; border: none; cursor: pointer;
      text-align: left; color: inherit; font: inherit;
      -webkit-tap-highlight-color: transparent;
    }
    .mn-mes-cab:hover  { background: rgba(255, 255, 255, 0.03); }
    .mn-mes-cab:active { background: rgba(255, 255, 255, 0.06); }
    .mn-mes-cab:focus-visible { outline: 2px solid var(--oro); outline-offset: -2px; }
    .mn-mes-flecha {
      flex: none; width: 18px; color: var(--text-muted); font-size: 0.9rem;
      transition: transform 0.18s ease;
    }
    .mn-mes[data-abierto="1"] .mn-mes-flecha { transform: rotate(90deg); }
    .mn-mes-nombre  { flex: 1; font-size: 1.05rem; font-weight: 600; min-width: 0; }
    .mn-mes-cuantos { font-size: 0.85rem; color: var(--text-muted); white-space: nowrap; }
    .mn-mes-total   { font-size: 1.05rem; font-weight: 700; white-space: nowrap; }

    /* El despliegue se abre suave sin que nadie tenga que medir alturas a
       mano: la rejilla pasa de 0fr a 1fr y el navegador anima hasta el alto
       que de verdad ocupa el contenido. */
    .mn-mes-panel {
      display: grid; grid-template-rows: 0fr;
      transition: grid-template-rows 0.25s ease;
    }
    .mn-mes[data-abierto="1"] .mn-mes-panel { grid-template-rows: 1fr; }
    .mn-mes-panel > div { overflow: hidden; }
    @media (prefers-reduced-motion: reduce) {
      .mn-mes-panel, .mn-mes-flecha { transition: none; }
    }

    .mn-cobro-item {
      margin: 0 18px 10px; padding: 11px 14px;
      border: 1px solid var(--border-subtle); border-left: 3px solid var(--positive);
      border-radius: 10px;
    }
    .mn-cobro-item:first-child { margin-top: 2px; }
    .mn-cobro-cab {
      display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap;
      margin-bottom: 7px;
    }
    .mn-cobro-per   { font-size: 1rem; color: var(--text-primary); }
    .mn-cobro-fecha { font-size: 0.85rem; color: var(--text-muted); white-space: nowrap; }
    .mn-cobro-linea {
      display: flex; justify-content: space-between; gap: 12px;
      font-size: 0.93rem; padding: 3px 0; color: var(--text-secondary);
    }
    .mn-cobro-linea.recibiste {
      margin-top: 4px; padding-top: 7px; border-top: 1px solid var(--border-subtle);
      color: var(--text-primary); font-weight: 700;
    }
    .mn-cobro-linea .mn-cobro-cifra { white-space: nowrap; }

    @media (max-width: 640px) {
      /* En pantalla angosta el "cuántos cobros" sobra antes que el total:
         el número es lo que se viene a ver. */
      .mn-mes-cuantos { display: none; }
      .mn-mes-cab     { padding: 12px 14px; }
      .mn-cobro-item  { margin-left: 14px; margin-right: 14px; }
    }

    /* Las dos pantallas del módulo se leen como el resto de Configuración:
       la tabla, dos puntos por encima de la de la app, y desplazándose
       dentro de su tarjeta antes que empujar la página de lado. */
    #section-mi_nomina table,
    #section-nomina table    { font-size: 16px; }
    #section-mi_nomina th,
    #section-nomina th       { font-size: 13px; }
    #section-mi_nomina .card-body,
    #section-nomina .card-body { overflow-x: auto; }

    @media (max-width: 640px) {
      /* En el teléfono el monto se va debajo del motivo: al lado no cabe
         sin partir la frase en una palabra por línea. */
      .mn-multa { padding: 12px 14px; }
      .mn-multa-monto { position: static; display: block; margin-top: 8px; }
      .mn-cobro-cifra { font-size: 2rem; }
      #section-mi_nomina th, #section-nomina th { padding-left: 8px; padding-right: 8px; }
      #section-mi_nomina td, #section-nomina td { padding-left: 8px; padding-right: 8px; }
    }

    /* Con la letra más grande, la tabla de cuatro columnas del contador de
       la IA no cabe en un teléfono. Que se desplace dentro de su cuadro es
       mejor que volver a encogerla o que empuje la página entera de lado. */
    #vision-uso-panel .card-body,
    #cuentas-usdt-panel .card-body   { overflow-x: auto; }
    /* Y en el teléfono se le quita aire a las celdas, para que haya que
       desplazar lo menos posible. */
    @media (max-width: 640px) {
      #vision-uso-panel th,
      #vision-uso-panel td { padding-left: 8px; padding-right: 8px; }
      #vision-uso-panel .card-body,
      #cuentas-usdt-panel .card-body { padding: 16px 14px; }
    }

    /* ── Configuración general (Día 1 cierre) ─────────────────────── */
    .cfg-list {
      display: flex;
      flex-direction: column;
      gap: 14px;
      margin-top: 16px;
    }
    .cfg-card {
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: 12px;
      padding: 16px 18px;
      display: flex;
      align-items: center;
      gap: 14px;
    }
    .cfg-card-info { flex: 1; min-width: 0; }
    .cfg-card-title {
      font-weight: 600;
      color: var(--text-dark);
      font-size: 0.95rem;
      margin-bottom: 4px;
    }
    .cfg-card-desc {
      font-size: 0.82rem;
      color: var(--text-muted);
      line-height: 1.4;
    }
    .cfg-card-meta {
      font-size: 0.72rem;
      color: var(--text-muted);
      margin-top: 6px;
    }
    .cfg-toggle {
      position: relative;
      width: 46px; height: 26px;
      flex-shrink: 0;
      display: inline-block;
    }
    .cfg-toggle input { opacity: 0; width: 0; height: 0; }
    .cfg-toggle .cfg-slider {
      position: absolute; inset: 0;
      background: #d4c3cd;
      border-radius: 99px;
      cursor: pointer;
      transition: background 0.2s;
    }
    .cfg-toggle .cfg-slider::before {
      content: '';
      position: absolute;
      width: 20px; height: 20px;
      left: 3px; top: 3px;
      background: #fff;
      border-radius: 50%;
      transition: transform 0.2s;
      box-shadow: 0 1px 3px rgba(0,0,0,0.18);
    }
    .cfg-toggle input:checked + .cfg-slider { background: #2d6a2d; }
    .cfg-toggle input:checked + .cfg-slider::before { transform: translateX(20px); }
    .cfg-toggle input:disabled + .cfg-slider { opacity: 0.55; cursor: not-allowed; }

    /* ── Sub-pestañas de Configuración general ─────────────────────────
       Las pestañas grandes de La Libreta, en pequeño y dentro de la hoja:
       misma letra y el mismo lenguaje de color (se reusan los siete colores
       de las hojas, --c-inicio … --c-admin). La elegida se pinta LLENA con
       su color y el texto oscuro encima; las demás quedan con el fondo de
       la hoja y su borde de color, que es lo que las distingue de un botón.

       Los siete colores son los mismos en tema claro y oscuro, así que el
       texto oscuro sobre el color llena contrasta igual en los dos. */
    .cfg-subtabs {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin: 16px 0 18px;
    }
    .cfg-subtab {
      font-family: var(--font-sans);
      font-size: 0.95rem;
      letter-spacing: 0.02em;
      padding: 9px 15px;
      border-radius: 11px 11px 4px 4px;
      cursor: pointer;
      color: var(--texto);
      background: var(--pagina2);
      border: 1px solid color-mix(in srgb, var(--ct) 65%, transparent);
      border-bottom: 3px solid var(--ct);
      transition: background .2s, color .2s, box-shadow .2s, transform .2s;
    }
    .cfg-subtab:hover {
      transform: translateY(-2px);
      box-shadow: 0 7px 18px -12px var(--ct);
    }
    .cfg-subtab:focus-visible { outline: 2px solid var(--ct); outline-offset: 2px; }
    .cfg-subtab.on {
      background: var(--ct);
      /* Oscuro fijo: encima del color lleno es lo único que se lee igual de
         bien con la luz encendida y apagada. */
      color: #17130a;
      font-weight: bold;
      border-color: var(--ct);
      box-shadow: 0 9px 22px -14px var(--ct);
      transform: none;
    }
    /* El panel que no toca queda fuera de la vista, pero YA CARGADO: sus
       datos se piden igual al entrar a Configuración, como antes. */
    .cfg-pane[hidden] { display: none; }
    @media (max-width: 640px) {
      .cfg-subtab { font-size: 0.88rem; padding: 8px 11px; }
    }

    /* ── Spinner ───────────────────────────────────────────────────── */
    .spinner {
      width: 24px; height: 24px;
      border: 3px solid var(--border);
      border-top-color: var(--gold);
      border-radius: 50%;
      animation: spin 0.7s linear infinite;
      margin: 40px auto;
    }
    @keyframes spin { to { transform: rotate(360deg); } }

    /* Highlight gold text */
    .text-gold   { color: var(--gold-dark); font-weight: 600; }
    .text-green  { color: #2d6a2d; }
    .text-red    { color: #8b2020; }
    .text-muted  { color: var(--text-muted); }
    .fw-serif    { font-family: var(--font-sans); font-size: 14px; font-weight: 600; color: #3d2535; }

    /* ═══════════════════════════════════════════════════════════════════
       REGISTRO-APP — DARK THEME OVERRIDES
       Aplica la paleta del mockup móvil sobre el chasis heredado.
       Por cascada gana sobre las reglas claritas de arriba.
    ══════════════════════════════════════════════════════════════════════ */

    body {
      font-family: var(--font-sans);
      background: var(--bg-base);
      color: var(--text-primary);
    }

    /* ── Tipografía serif para encabezados ─────────────────────────── */
    h1, h2, h3,
    .section-title,
    .card-title,
    .modal-title,
    .login-brand,
    .login-brand span,
    .login-sub{
      font-family: var(--font-sans);
      font-style: normal;
      color: var(--text-muted);
      font-weight: 500;
      letter-spacing: 0.14em;
    }

    /* ── Scrollbar discreta ────────────────────────────────────────── */
    ::-webkit-scrollbar { width: 6px; height: 6px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: var(--border-soft); border-radius: 99px; }
    ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

    /* ── Sidebar ───────────────────────────────────────────────────── */
    .nav-item {
      color: var(--text-secondary);
    }
    .nav-item:hover {
      background: rgba(201,169,97,0.08);
      color: var(--gold);
    }
    .nav-item.active {
      background: rgba(201,169,97,0.12);
      color: var(--gold);
      font-weight: 500;
      border: 1px solid var(--border-gold);
    }
    .nav-item.active .nav-icon,
    .nav-item:hover .nav-icon { color: var(--gold); }
    .nav-icon { color: var(--text-muted); }

    /* ── Cards ─────────────────────────────────────────────────────── */
    .card {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md);
      box-shadow: var(--shadow-card);
    }
    .card-header {
      border-bottom: 1px solid var(--border-subtle);
    }
    .card-title { color: var(--text-primary); }

    /* ── KPI cards ─────────────────────────────────────────────────── */
    .kpi-card {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md);
      box-shadow: var(--shadow-card);
    }
    .kpi-card.gold {
      background: var(--bg-gold-grad);
      border-color: var(--border-gold);
      box-shadow: var(--shadow-gold);
    }
    .kpi-card.gold .kpi-label  { color: var(--text-on-gold); opacity: 0.7; }
    .kpi-card.gold .kpi-value  { color: var(--text-primary); }
    .kpi-card.gold .kpi-icon   { background: rgba(0,0,0,0.25); color: var(--gold-bright); }

    .kpi-card.rose::before,
    .kpi-card.teal::before { background: linear-gradient(90deg, var(--gold-dim), var(--gold)); }

    .kpi-card.rose   .kpi-icon { background: rgba(201,169,97,0.10); color: var(--gold); }
    .kpi-card.teal   .kpi-icon { background: rgba(201,169,97,0.10); color: var(--gold); }

    .kpi-label { color: var(--text-muted); }
    .kpi-value {
      font-family: var(--font-sans);
      font-weight: 700;
      color: var(--text-primary);
    }

    /* ── Section titles + gold line ────────────────────────────────── */
    .section-title { color: var(--text-primary); font-size: 27.2px; }
    .section-sub   { color: var(--text-muted); }
    .gold-line { background: linear-gradient(90deg, var(--gold), transparent); }

    /* ── Tablas ────────────────────────────────────────────────────── */
    thead tr { background: var(--bg-elevated); }
    th {
      color: var(--text-muted);
      border-bottom: 1px solid var(--border-subtle);
    }
    td {
      color: var(--text-secondary);
      border-bottom: 1px solid var(--border-subtle);
    }
    tbody tr:hover { background: rgba(255,255,255,0.02); }

    /* ── Badges ────────────────────────────────────────────────────── */
    .badge-green  { background: var(--positive-bg);     color: var(--positive); }

    /* ── Botones ───────────────────────────────────────────────────── */
    .btn-primary {
      background: var(--bg-gold-grad);
      color: var(--text-on-gold);
      border: 1px solid var(--border-gold);
    }
    .btn-primary:hover {
      background: linear-gradient(135deg, #34270f 0%, #4a3914 100%);
      color: var(--text-primary);
    }
    .btn-gold {
      background: var(--gold);
      color: #1a1408;
      border: 1px solid var(--border-gold);
    }
    .btn-gold:hover {
      background: var(--gold-bright);
      color: #1a1408;
    }
    .btn-outline {
      background: transparent;
      color: var(--text-primary);
      border: 1px solid var(--border-soft);
    }
    .btn-outline:hover {
      background: rgba(255,255,255,0.04);
      border-color: var(--border-strong);
    }
    .btn-danger {
      background: transparent;
      color: var(--negative);
      border: 1px solid color-mix(in srgb, var(--negative) 30%, transparent);
    }
    .btn-danger:hover {
      background: var(--negative-bg);
    }

    /* ── Formularios ───────────────────────────────────────────────── */
    label { color: var(--text-muted); }
    input, select, textarea {
      background: var(--bg-input);
      border: 1px solid var(--border-soft);
      color: var(--text-primary);
      color-scheme: dark;
    }
    input::placeholder, textarea::placeholder { color: var(--text-dim); }
    input:focus, select:focus, textarea:focus {
      /* El anillo de foco lo pone la regla única del final. */
      border-color: var(--gold);
      box-shadow: 0 0 0 3px rgba(201,169,97,0.18);
      background: var(--bg-elevated);
    }
    select option { background: var(--bg-card); color: var(--text-primary); }

    /* ── Alertas ───────────────────────────────────────────────────── */
    .alert-success {
      background: var(--positive-bg);
      border: 1px solid rgba(90,181,116,0.3);
      color: var(--positive);
    }
    .alert-error {
      background: var(--negative-bg);
      border: 1px solid rgba(217,116,116,0.3);
      color: var(--negative);
    }

    /* ── Empty state ───────────────────────────────────────────────── */
    .empty { color: var(--text-muted); }
    .empty-icon { color: var(--gold-dim); opacity: 0.5; }

    /* ── Text helpers ──────────────────────────────────────────────── */
    .text-gold  { color: var(--gold); font-weight: 600; }
    .text-green { color: var(--positive); }
    .text-red   { color: var(--negative); }
    .text-muted { color: var(--text-muted); }
    .fw-serif   { font-family: var(--font-sans); font-weight: 600; color: var(--text-primary); }

    /* ── Modal overlay + modal card ────────────────────────────────── */
    .modal {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      box-shadow: 0 8px 40px rgba(0,0,0,0.5);
    }
    .modal-header, .modal-footer {
      border-color: var(--border-subtle);
    }
    .modal-title { color: var(--text-primary); }
    .modal-close {
      background: var(--bg-elevated);
      color: var(--text-muted);
    }
    .modal-close:hover {
      background: rgba(255,255,255,0.05);
      color: var(--text-primary);
    }

    /* ── Login screen ──────────────────────────────────────────────── */
    #login-screen { background: var(--bg-base); }
    .login-card {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      box-shadow: 0 8px 40px rgba(0,0,0,0.5), var(--shadow-gold);
    }
    .login-brand { color: var(--text-primary); }
    #login-error {
      background: var(--negative-bg);
      border: 1px solid color-mix(in srgb, var(--negative) 30%, transparent);
      color: var(--negative);
    }

    /* ═══════════════════════════════════════════════════════════════════
       MURO DE ACTIVIDAD + PENDIENTES POR AUTORIZACIÓN
    ══════════════════════════════════════════════════════════════════════ */
    /* Si la franja de KPIs no se pobló (kpis-hoy falló o devolvió null),
       colapsarla para que no quede un cuadro vacío "flotando" sobre el
       título "Actividad reciente". */

    #muro-content { display: flex; flex-direction: column; gap: 8px; }
    .muro-day-sep {
      display: flex;
      align-items: center;
      gap: 12px;
      color: var(--text-muted);
      font-size: 0.74rem;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      font-weight: 600;
      margin: 14px 0 4px;
    }
    .muro-day-sep::before,
    .muro-day-sep::after {
      content: '';
      flex: 1;
      height: 1px;
      background: var(--border-subtle);
    }
    /* Lista de Actividad reciente — solo lectura (no clickeable).
       Para abrir el detalle de una transacción, el usuario va a
       Registro de Ingresos / Resumen. */
    .muro-card {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 12px 14px;
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-left: 4px solid var(--text-dim);
      border-radius: var(--radius-sm);
      cursor: default;
    }
    /* Una tarjeta que abre el detalle se comporta como lo que es: se puede
       pulsar, y se nota antes de pulsarla. Las que no tienen transacción
       detrás (un cierre, un aviso) se quedan como estaban. */
    .muro-card.abrible { cursor: pointer; }
    .muro-card.abrible:focus-visible {
      outline: 2px solid var(--gold);
      outline-offset: 2px;
    }
    .muro-card.pendiente {
      border-color: var(--border-gold);
      box-shadow: 0 0 0 1px rgba(201,169,97,0.18);
    }
    .muro-card-icon {
      width: 32px;
      height: 32px;
      border-radius: 8px;
      background: var(--bg-elevated);
      display: flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      color: var(--text-secondary);
      font-size: 17.6px;
    }
    .muro-card-body { flex: 1; min-width: 0; }
    .muro-card-top {
      display: flex;
      align-items: baseline;
      gap: 8px;
      flex-wrap: wrap;
    }
    .muro-card-titulo {
      color: var(--text-primary);
      font-weight: 600;
      font-size: 0.92rem;
    }
    .muro-card-actor {
      color: var(--text-muted);
      font-size: 0.78rem;
    }
    .muro-card-resumen {
      color: var(--text-secondary);
      font-size: 0.82rem;
      margin-top: 2px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .muro-card-tiempo {
      color: var(--text-muted);
      font-size: 0.74rem;
      flex-shrink: 0;
      margin-left: 8px;
    }
    .muro-card-badge {
      display: inline-block;
      background: rgba(229,160,94,0.18);
      border: 1px solid rgba(229,160,94,0.45);
      color: var(--warning);
      font-size: 0.7rem;
      font-weight: 600;
      padding: 1px 8px;
      border-radius: 999px;
      margin-left: 4px;
    }
    .muro-empty {
      text-align: center;
      padding: 60px 20px;
      color: var(--text-muted);
    }
    .muro-empty-icon {
      font-size: 38.4px;
      color: var(--gold-dim);
      opacity: 0.5;
      margin-bottom: 10px;
    }

    /* ── Pendientes por autorización ─────────────────────────────────── */
    .pa-btn {
      padding: 6px 12px;
      border-radius: var(--radius-sm);
      font-weight: 600;
      font-size: 0.78rem;
      border: 1px solid transparent;
      cursor: pointer;
      transition: all 0.15s;
    }
    .pa-btn-aprobar {
      background: linear-gradient(135deg, #166534 0%, #15803d 100%);
      color: #d1fae5;
      border-color: #14532d;
      box-shadow: 0 4px 14px rgba(22,101,52,0.3);
    }
    .pa-btn-aprobar:hover {
      transform: translateY(-1px);
      box-shadow: 0 6px 18px rgba(22,101,52,0.4);
    }
    .pa-btn-rechazar {
      background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%);
      color: #fee2e2;
      border-color: #7f1d1d;
    }
    .pa-btn-rechazar:hover {
      transform: translateY(-1px);
    }

    /* ── Clientes internet (Sprint martes 9 jun) ──────────────────────── */
    .ci-header {
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      gap: 16px;
      flex-wrap: wrap;
    }
    .ci-toolbar {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 12px;
      margin: 14px 0;
      flex-wrap: wrap;
    }
    /* El contenedor apila SUS DOS FILAS, una encima de otra. Era
       `display:flex` en fila con wrap: como sus hijos son las dos líneas
       rotuladas, en una pantalla ancha cabían las dos al lado y se veían como
       una sola tira de cinco pestañas — que es justo lo que los rótulos
       vinieron a evitar (Rich, 23-oct). */
    .ci-tabs { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
    .ci-tab {
      padding: 6px 12px; border-radius: 999px;
      background: var(--bg-elevated); border: 1px solid var(--border-subtle);
      color: var(--text-secondary); font-size: 0.8rem; cursor: pointer;
      transition: all .15s;
    }
    .ci-tab:hover { border-color: var(--gold-dim); }
    .ci-tab.active {
      background: var(--bg-card); border-color: var(--gold-bright);
      color: var(--gold-bright);
    }
    .ci-tab-count { margin-left: 6px; font-size: 0.74rem; color: var(--text-muted); }
    /* Las pestañas van en dos líneas rotuladas: arriba la cobranza (lo
       nuestro), abajo el servicio que manda WispHub. Sin el rótulo, las
       cinco parecían la misma pregunta y sus números parecían descuadrar. */
    .ci-tabs-fila {
      display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px;
    }
    .ci-tabs-rotulo {
      font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em;
      color: var(--text-muted); min-width: 112px;
    }
    .ci-tabs-rotulo.wh { color: var(--warning); }
    .ci-tabs-nota {
      font-size: 0.76rem; color: var(--text-muted); line-height: 1.4; margin: 2px 0 2px;
    }
    /* El estado que manda WispHub. "Activo" se pinta apagado porque es lo
       normal; lo que no es activo se ve de lejos. */
    .ci-badge-wh {
      display: inline-block; padding: 2px 8px; border-radius: 999px;
      font-size: 0.7rem; font-weight: 600; letter-spacing: 0.02em;
      border: 1px solid var(--border-subtle); color: var(--text-muted);
    }
    .ci-badge-wh.ok       { color: var(--text-muted); }
    .ci-badge-wh.malo     { color: var(--warning); border-color: var(--warning); font-weight: 700; }
    .ci-badge-wh.sin-dato { color: var(--text-muted); font-style: italic; }
    #ci-busqueda {
      min-width: 280px; padding: 8px 12px;
      background: var(--bg-input); border: 1px solid var(--border-soft);
      border-radius: 8px; color: var(--text-primary); font-family: inherit;
    }
    .ci-table {
      width: 100%; border-collapse: collapse;
      background: var(--bg-card); border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md); overflow: hidden;
    }
    .ci-table th, .ci-table td {
      padding: 10px 12px; text-align: left;
      border-bottom: 1px solid var(--border-subtle);
      font-size: 0.84rem; vertical-align: middle;
    }
    .ci-table thead th {
      color: var(--text-muted); font-size: 0.72rem;
      text-transform: uppercase; letter-spacing: 0.06em;
      background: var(--bg-elevated);
    }
    .ci-table tbody tr { cursor: pointer; transition: background .12s; }
    .ci-table tbody tr:hover { background: var(--bg-elevated); }
    .ci-badge {
      display: inline-block; padding: 2px 8px; border-radius: 999px;
      font-size: 0.7rem; font-weight: 600; letter-spacing: 0.02em;
    }
    .ci-badge.activo     { background: rgba(90,181,116,0.15);  color: #5ab574; }
    .ci-badge.moroso     { background: rgba(229,160,94,0.18);  color: var(--warning); }
    .ci-badge.suspendido { background: rgba(150,150,150,0.18); color: var(--text-muted); }
    .ci-badge.cancelado  { background: rgba(215,119,119,0.18); color: #d77; }
    .ci-empty {
      padding: 60px 20px; text-align: center; color: var(--text-muted);
      border: 1px dashed var(--border-subtle); border-radius: var(--radius-md);
    }
    /* El buscador manda: ocupa toda la línea y es lo primero que se ve. */
    .ci-buscador { margin: 14px 0 10px; }
    .ci-buscador input[type="search"] {
      width: 100%; padding: 13px 16px; font-size: 16.5px;
      background: var(--bg-elevated); color: var(--text-primary);
      border: 1px solid var(--border-soft); border-radius: var(--radius-md);
    }
    .ci-buscador input[type="search"]:focus {
      border-color: var(--gold); background: var(--bg-surface);
    }
    /* La pantalla de reposo: lo que se ve al entrar, sin los 234 encima. */
    .ci-reposo { margin-top: 6px; }
    .ci-reposo-pista {
      padding: 26px 20px; text-align: center; color: var(--text-muted);
      border: 1px dashed var(--border-subtle); border-radius: var(--radius-md);
      line-height: 1.5;
    }
    .ci-marcados {
      border: 1px solid var(--warning); border-left-width: 4px;
      border-radius: var(--radius-md); background: var(--bg-elevated);
      padding: 12px 14px; margin-bottom: 12px; line-height: 1.45;
    }
    .ci-marcados-fila {
      padding: 7px 0; border-top: 1px solid var(--border-subtle);
      cursor: pointer; font-size: 0.93rem;
    }
    .ci-marcados-fila:first-of-type { border-top: none; }
    .ci-marcados-fila:hover { color: var(--gold-bright); }
    .ci-conteo {
      display: flex; justify-content: space-between; align-items: center;
      gap: 12px; flex-wrap: wrap; margin-top: 12px;
      color: var(--text-muted); font-size: 0.9rem;
    }
    /* ── LA CAJA DE LA LISTA ───────────────────────────────────────────
       Alto fijo y recorrido propio: la ruedita mueve los clientes de dentro
       y la página de atrás se queda quieta (`overscroll-behavior: contain`,
       que además impide que al llegar al final el movimiento se contagie a
       la página). Mide lo mismo con 20 clientes que con 236.

       El alto NO es un número elegido a dedo: lo mide ciAjustarCaja() al
       pintar, quedándose con lo que sobra de pantalla desde donde empieza
       la caja. Así la sección abierta cabe en una pantalla en el monitor
       del local, en un portátil y en el teléfono, que es lo que pedía el
       encargo; lo de abajo es sólo el valor de arranque. */
    .ci-caja {
      /* Valor de arranque. El definitivo lo pone ciAjustarCaja() al pintar:
         la caja se queda con lo que sobra de pantalla, para que la sección
         abierta quepa entera sin tener que bajar. */
      max-height: clamp(200px, 46vh, 620px);
      overflow-y: auto; overflow-x: auto;
      overscroll-behavior: contain;
      -webkit-overflow-scrolling: touch;
      border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
      background: var(--bg-card);
    }
    /* `border-collapse: separate` NO es un capricho: con `collapse`, que es
       lo que usa la tabla por defecto, Chrome no respeta el `sticky` de la
       cabecera y los títulos de las columnas se van con el recorrido. */
    .ci-caja .ci-table {
      border: none; border-radius: 0;
      border-collapse: separate; border-spacing: 0;
      /* El `overflow: hidden` que trae .ci-table (para redondearle las
         esquinas) convierte a la tabla en su propio recuadro de recorte, y
         entonces la cabecera pegada se queda pegada A LA TABLA — o sea, se
         va con las filas. Dentro de la caja, la que recorta es la caja. */
      overflow: visible;
    }
    /* La cabecera se queda arriba mientras se recorre: sin esto, a la fila
       veinte ya nadie sabe qué columna está mirando. */
    .ci-caja .ci-table thead th {
      position: sticky; top: 0; z-index: 2;
      background: var(--bg-elevated);
      border-bottom: 1px solid var(--border-subtle);
    }
    /* Una línea por cliente, y apretada: es lo que hace que quepan unos
       veinte a la vez en una caja que todavía cabe en la pantalla. */
    .ci-caja .ci-table td {
      white-space: nowrap; padding: 2px 12px; font-size: 0.78rem;
      line-height: 1.3;
      border-bottom: 1px solid var(--border-subtle);
    }
    .ci-caja .ci-table thead th { padding: 5px 12px; }
    .ci-caja .ci-table td span { font-size: 0.95em; }
    .ci-caja .ci-table .ci-badge { padding: 1px 7px; }
    /* ── EL DESPLEGABLE ────────────────────────────────────────────────
       Cerrado es una línea. Es un botón, pero no parece un botón: parece el
       renglón de una libreta que se abre. */
    .ci-desplegable {
      display: flex; align-items: center; gap: 10px; width: 100%;
      margin-top: 12px; padding: 10px 14px; text-align: left;
      background: var(--bg-elevated); color: var(--text-secondary);
      border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
      font-family: inherit; font-size: 0.9rem; cursor: pointer;
    }
    .ci-desplegable:hover { border-color: var(--gold-dim); color: var(--text-primary); }
    .ci-desplegable.abierta {
      border-color: var(--gold-dim); color: var(--text-primary);
      border-bottom-left-radius: 0; border-bottom-right-radius: 0;
      margin-bottom: 0;
    }
    .ci-desplegable.abierta + .ci-caja {
      border-top-left-radius: 0; border-top-right-radius: 0; border-top: none;
    }
    .ci-desplegable-flecha { color: var(--gold-bright); font-size: 0.8rem; }
    .ci-desplegable-texto { font-weight: 600; }
    .ci-desplegable-pista {
      margin-left: auto; color: var(--text-muted); font-size: 0.78rem;
    }
    /* La salida a WispHub cuando el cliente no está en la lista. */
    .ci-wh-zona {
      margin-top: 14px; padding: 12px 14px; line-height: 1.45;
      border: 1px solid var(--border-soft); border-radius: var(--radius-md);
      background: var(--bg-elevated);
    }
    .ci-wh-texto {
      font-size: 0.88rem; color: var(--text-secondary); margin-bottom: 10px;
    }
    @media (max-width: 640px) {
      .ci-buscador input[type="search"] { font-size: 16px; padding: 12px 14px; }
      .ci-conteo { justify-content: center; text-align: center; }
      /* En pantalla chica sobran las columnas menos urgentes: el próximo
         corte se deduce del mes pagado, y las dos están en la ficha. */
      .ci-table .ci-col-corte { display: none; }
      .ci-table th, .ci-table td { padding: 9px 8px; font-size: 0.8rem; }
      .ci-caja .ci-table td { padding: 3px 8px; font-size: 0.78rem; }
      /* En el teléfono la caja se queda algo más baja: con el teclado
         abierto, media pantalla es todo lo que hay. */
      .ci-caja { max-height: clamp(180px, 42vh, 420px); }
      /* La pista del desplegable se va a su propia línea en vez de apretar
         el conteo contra el borde. */
      .ci-desplegable { flex-wrap: wrap; }
      .ci-desplegable-pista { margin-left: 26px; }
    }

    /* Ficha de cliente */
    .ci-ficha-header {
      display: flex; justify-content: space-between; align-items: center;
      gap: 12px; margin-bottom: 18px; flex-wrap: wrap;
    }
    .ci-ficha-name {
      font-family: var(--font-serif);
      font-size: 22.4px; color: var(--gold-bright);
    }
    .ci-ficha-num { color: var(--text-muted); font-size: 0.86rem; margin-left: 10px; }
    .ci-ficha-grid {
      display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
    }
    @media (max-width: 800px) { .ci-ficha-grid { grid-template-columns: 1fr; } }
    .ci-ficha-card {
      background: var(--bg-card); border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md); padding: 14px 18px;
    }
    .ci-ficha-card h4 {
      margin: 0 0 10px; font-size: 0.82rem;
      color: var(--gold-dim); text-transform: uppercase; letter-spacing: 0.08em;
    }
    .ci-ficha-row {
      display: flex; justify-content: space-between;
      padding: 5px 0; font-size: 0.86rem;
      border-bottom: 1px solid var(--border-subtle);
    }
    .ci-ficha-row:last-of-type { border-bottom: none; }
    .ci-ficha-row .lbl { color: var(--text-muted); }
    .ci-ficha-row .val { color: var(--text-primary); font-weight: 500; text-align: right; }
    .ci-ficha-actions {
      display: flex; gap: 8px; margin-top: 18px; flex-wrap: wrap;
    }

    .pa-empty {
      text-align: center;
      padding: 80px 20px;
      color: var(--text-muted);
    }
    .pa-empty-icon {
      font-size: 48px;
      color: var(--gold-dim);
      opacity: 0.5;
      margin-bottom: 14px;
    }
    .pa-counter {
      color: var(--gold);
      font-weight: 600;
      font-size: 0.86rem;
      margin-left: 8px;
    }

    /* ── Saldo Pago Listo ───────────────────────────────────────────── */
    .spl-hero {
      display: flex;
      align-items: center;
      gap: 18px;
      padding: 22px 24px;
      background: linear-gradient(135deg, rgba(201,169,97,0.10), rgba(201,169,97,0.02));
      border: 1px solid var(--border-gold);
      border-left-width: 4px;
      border-radius: var(--radius-md);
      margin-bottom: 18px;
      flex-wrap: wrap;
    }
    .spl-hero.low {
      background: linear-gradient(135deg, rgba(229,160,94,0.15), rgba(229,160,94,0.03));
      border-color: var(--warning);
      border-left-color: var(--warning);
    }
    .spl-hero.red {
      background: linear-gradient(135deg, rgba(215,119,119,0.18), rgba(215,119,119,0.04));
      border-color: var(--negative);
      border-left-color: var(--negative);
    }
    .spl-hero-info { flex: 1; min-width: 220px; }
    .spl-hero-label {
      color: var(--text-muted);
      font-size: 0.74rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      margin-bottom: 4px;
    }
    .spl-hero-value {
      font-family: var(--font-sans);
      font-variant-numeric: tabular-nums;
      color: var(--gold-bright);
      font-weight: 700;
      font-size: 35.2px;
      letter-spacing: 0.01em;
      line-height: 1.1;
    }
    .spl-hero.low .spl-hero-value { color: var(--warning); }
    .spl-hero.red .spl-hero-value { color: var(--negative); }
    .spl-hero-meta {
      color: var(--text-muted);
      font-size: 0.78rem;
      margin-top: 6px;
    }
    .spl-hero-warning {
      display: inline-block;
      margin-top: 8px;
      padding: 4px 10px;
      border-radius: 999px;
      font-size: 0.74rem;
      font-weight: 600;
      background: rgba(229,160,94,0.18);
      color: var(--warning);
    }
    .spl-hero.red .spl-hero-warning {
      background: rgba(215,119,119,0.22);
      color: var(--negative);
    }
    /* Campo de hora de 24 horas (inputHora24): angosto y con cifras de igual
       ancho, para que 07:30 y 17:45 queden alineados en la tabla de horarios. */
    input.hora24 { font-variant-numeric: tabular-nums; letter-spacing: .04em; }
    .hor-tabla input.hora24 { width: 76px; text-align: center; padding: 6px 4px; }
    .spl-mov-table {
      width: 100%;
      border-collapse: collapse;
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md);
      overflow: hidden;
      font-size: 0.85rem;
    }
    .spl-mov-table th, .spl-mov-table td {
      padding: 8px 12px;
      text-align: left;
      border-bottom: 1px solid var(--border-subtle);
      vertical-align: middle;
    }
    .spl-mov-table thead th {
      color: var(--text-muted);
      font-size: 0.72rem;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      background: var(--bg-elevated);
      font-weight: 600;
    }
    .spl-mov-table tbody tr:last-child td { border-bottom: none; }
    .spl-mov-table tbody tr:hover { background: var(--bg-elevated); }
    .spl-badge {
      display: inline-block;
      padding: 2px 8px;
      border-radius: 999px;
      font-size: 0.7rem;
      font-weight: 600;
      letter-spacing: 0.02em;
    }
    .spl-badge.abono   { background: rgba(90,181,116,0.15); color: var(--positive); }
    .spl-badge.consumo { background: rgba(215,119,119,0.15); color: var(--negative); }
    .spl-badge.anulado { background: rgba(150,150,150,0.18); color: var(--text-muted); }
    .spl-mov-table tr.spl-row-anulado td { opacity: 0.5; text-decoration: line-through; }
    .spl-mov-table tr.spl-row-anulado td:first-child,
    .spl-mov-table tr.spl-row-anulado td:nth-child(2),
    .spl-mov-table tr.spl-row-anulado td:nth-child(6),
    .spl-mov-table tr.spl-row-anulado td:last-child { text-decoration: none; }
    .spl-row-btn {
      padding: 3px 8px;
      margin-left: 4px;
      border-radius: 6px;
      font-size: 0.82rem;
      border: 1px solid var(--border-soft);
      background: var(--bg-elevated);
      color: var(--text-secondary);
      cursor: pointer;
      transition: all 0.12s;
    }
    .spl-row-btn:hover { background: var(--bg-card); border-color: var(--gold-dim); }
    .spl-row-btn.edit:hover { color: var(--gold-bright); border-color: var(--gold); }
    .spl-row-btn.del:hover  { color: var(--negative); border-color: var(--negative); background: rgba(215,119,119,0.06); }
    .spl-monto {
      font-family: var(--font-sans);
      font-variant-numeric: tabular-nums;
      font-weight: 700;
      white-space: nowrap;
    }
    .spl-monto.abono   { color: var(--positive); }
    .spl-monto.consumo { color: var(--negative); }
    .spl-saldo-resultante {
      font-family: var(--font-sans);
      font-variant-numeric: tabular-nums;
      color: var(--gold-bright);
      font-weight: 600;
    }
    .spl-empty {
      text-align: center;
      padding: 50px 20px;
      color: var(--text-muted);
      border: 1px dashed var(--border-subtle);
      border-radius: var(--radius-md);
    }

    /* ── Verificación: lista compacta tipo fila ──────────────────────── */
    .ver-list {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-md);
      overflow: hidden;
    }
    .ver-row {
      display: grid;
      grid-template-columns: 28px 92px 1fr auto auto;
      gap: 10px;
      align-items: center;
      padding: 8px 12px;
      border-bottom: 1px solid var(--border-subtle);
      font-size: 0.85rem;
      transition: background 0.12s;
    }
    .ver-row:last-of-type { border-bottom: none; }
    .ver-row:hover { background: var(--bg-elevated); }
    .ver-row.observada {
      background: rgba(229,160,94,0.06);
      border-left: 3px solid var(--warning);
      padding-left: 9px;
    }
    .ver-row.observada:hover { background: rgba(229,160,94,0.10); }

    .ver-row-check {
      width: 16px; height: 16px;
      cursor: pointer;
      accent-color: var(--gold);
    }
    .ver-row-thumb {
      width: 44px; height: 44px;
      border-radius: 6px;
      background: var(--bg-elevated);
      border: 1px solid var(--border-soft);
      overflow: hidden;
      display: flex; align-items: center; justify-content: center;
      cursor: zoom-in;
      flex-shrink: 0;
      position: relative;
    }
    .ver-row-thumb img {
      width: 100%; height: 100%;
      object-fit: cover;
      display: block;
    }
    /* Stack de 2 miniaturas (báscula + comprobante en la misma fila).
       Ancho fijo total = 2 thumbs de 44px + 4px gap = 92px. Coincide con
       la columna 2 del grid de .ver-row. SIN width:100% en los hijos
       (eso, combinado con flex-shrink:0 de .ver-row-thumb, hacía que
       cada thumb intentara medir 92px y los dos se desbordaran encima
       de la columna de datos). */
    .ver-row-thumb-stack {
      display: flex; gap: 4px;
      width: 92px; height: 44px;
    }
    /* La foto de la báscula en la revisión del cierre: más grande que una
       miniatura de lista, porque aquí es la prueba —se mira antes de tocar
       nada— y con un clic se abre en el visor, con lupa. */
    .cierre-rev-thumb { width: 112px; height: 112px; }
    @media (max-width: 640px) { .cierre-rev-thumb { width: 84px; height: 84px; } }
    .ver-row-thumb-stack .ver-row-thumb {
      width: 44px; height: 44px;
      flex: 0 0 44px;
    }
    .ver-row-thumb.empty {
      color: var(--text-dim);
      font-size: 0.6rem;
      cursor: default;
      text-align: center;
    }

    .ver-row-meta {
      display: flex; flex-direction: column;
      min-width: 0;
      line-height: 1.25;
    }
    .ver-row-titulo {
      color: var(--text-primary);
      font-weight: 600;
      font-size: 0.86rem;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .ver-row-titulo .ver-row-id {
      color: var(--text-muted);
      font-weight: 500;
      font-size: 0.74rem;
      margin-left: 4px;
    }
    .ver-row-sub {
      color: var(--text-muted);
      font-size: 0.74rem;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .ver-row-obs-marker {
      display: inline-block;
      margin-left: 6px;
      color: var(--warning);
      font-size: 0.7rem;
      font-weight: 600;
      cursor: help;
    }

    /* ── Revisión automática con IA ──────────────────────────────────────
       Tres cosas tienen que distinguirse de un vistazo en esta lista:
       lo que aprobó la máquina, lo que la máquina mandó al admin (y por
       qué), y lo que el admin ya revisó con sus ojos. Si las tres se vieran
       igual, la revisión automática no habría ahorrado nada. */
    .ver-ia-bar {
      display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
      padding: 10px 14px; margin: 0 0 14px 0;
      border: 1px solid var(--border-soft);
      border-radius: var(--radius);
      background: var(--bg-elevated);
    }
    .ver-ia-bar-texto { font-size: 0.82rem; color: var(--text-secondary); flex: 1; min-width: 200px; }
    .ver-ia-bar-texto b { color: var(--text-primary); }
    .ver-ia-bar-sub { font-size: 0.72rem; color: var(--text-muted); margin-top: 2px; }

    /* Motivo por el que la IA mandó una transacción al admin. Ocupa su
       propia línea a propósito: es lo que hay que leer antes de mirar la
       foto, no una etiqueta más al lado del monto. */
    .ver-ia-motivo {
      margin-top: 6px;
      padding: 7px 10px;
      border-radius: 6px;
      font-size: 0.78rem;
      line-height: 1.4;
      background: rgba(224, 90, 90, 0.08);
      border-left: 3px solid var(--negative);
      color: var(--text-secondary);
    }
    /* Un comprobante reciclado no es una discrepancia más: es lo más grave
       que esta revisión puede encontrar. */
    .ver-ia-motivo.grave {
      background: rgba(224, 90, 90, 0.16);
      border-left-width: 4px;
      color: var(--text-primary);
      font-weight: 500;
    }
    .ver-ia-motivo.leve {
      background: rgba(229, 160, 94, 0.10);
      border-left-color: var(--warning);
    }
    .ver-row-ia-marker {
      display: inline-block;
      margin-left: 6px;
      padding: 1px 7px;
      border-radius: 999px;
      font-size: 0.68rem;
      font-weight: 700;
      white-space: nowrap;
      cursor: help;
      color: var(--positive);
      background: rgba(90, 180, 120, 0.10);
      border: 1px solid rgba(90, 180, 120, 0.35);
    }
    .ver-row-ia-marker.revision {
      color: var(--negative);
      background: rgba(224, 90, 90, 0.10);
      border-color: rgba(224, 90, 90, 0.35);
    }
    .ver-row-ia-marker.admin {
      color: var(--gold-bright);
      background: rgba(191, 155, 74, 0.10);
      border-color: rgba(191, 155, 74, 0.35);
    }

    /* Marca "Vision no confirmó el comprobante" en la fila de verificación.
       Más fuerte que la nota: fondo tenue + borde para que salte a la vista. */
    .ver-row-vision-marker {
      display: inline-block;
      margin-left: 6px;
      padding: 1px 7px;
      border-radius: 999px;
      color: var(--negative);
      background: rgba(224, 90, 90, 0.10);
      border: 1px solid rgba(224, 90, 90, 0.35);
      font-size: 0.68rem;
      font-weight: 700;
      cursor: help;
      white-space: nowrap;
    }

    /* Regla del sobrepeso sano: el oro pesado debe ser un poco MAYOR que lo
       registrado. Si pesó igual o menos, la fila lo grita en rojo. Si sobró
       muchísimo, es sólo una observación (ámbar): no es una anomalía de
       dinero, pero puede ser algo pesado sin anotar. */
    .ver-row-peso-marker {
      display: inline-block;
      margin-left: 6px;
      padding: 1px 7px;
      border-radius: 999px;
      color: var(--negative);
      background: rgba(224, 90, 90, 0.10);
      border: 1px solid rgba(224, 90, 90, 0.35);
      font-size: 0.68rem;
      font-weight: 700;
      cursor: help;
      white-space: nowrap;
    }
    .ver-row-peso-marker.observacion {
      color: var(--warning);
      background: rgba(229, 160, 94, 0.10);
      border-color: rgba(229, 160, 94, 0.38);
    }

    .ver-row-monto {
      font-family: var(--font-sans);
      font-variant-numeric: tabular-nums;
      color: var(--gold-bright);
      font-weight: 700;
      font-size: 0.9rem;
      text-align: right;
      line-height: 1.2;
      white-space: nowrap;
    }
    .ver-row-monto .ver-row-monto-sub {
      display: block;
      color: var(--text-muted);
      font-weight: 500;
      font-size: 0.7rem;
      letter-spacing: 0;
    }

    .ver-row-actions {
      display: flex; gap: 6px;
      align-items: center;
      flex-wrap: wrap;
      justify-content: flex-end;
    }
    .ver-row-btn {
      padding: 5px 10px;
      border-radius: 6px;
      font-size: 0.74rem;
      font-weight: 600;
      border: 1px solid transparent;
      cursor: pointer;
      transition: all 0.12s;
      white-space: nowrap;
    }
    .ver-row-btn.ok {
      background: linear-gradient(135deg,#166534 0%,#15803d 100%);
      color: #d1fae5;
      border-color: #14532d;
    }
    .ver-row-btn.ok:hover { transform: translateY(-1px); box-shadow: 0 3px 10px rgba(22,101,52,0.35); }
    .ver-row-btn.obs {
      background: linear-gradient(135deg,#92400e 0%,#b45309 100%);
      color: #fff7ed;
      border-color: #78350f;
    }
    .ver-row-btn.obs:hover { transform: translateY(-1px); }

    /* Panel expandible de observación bajo la fila */
    .ver-row-expand {
      grid-column: 1 / -1;
      display: none;
      padding: 10px 12px 12px;
      background: rgba(229,160,94,0.04);
      border-top: 1px dashed rgba(229,160,94,0.4);
      margin: 4px -12px -8px;
    }
    .ver-row.expandida .ver-row-expand { display: block; }
    .ver-row-expand-existing {
      font-size: 0.78rem;
      color: var(--text-secondary);
      background: rgba(229,160,94,0.08);
      border-left: 3px solid var(--warning);
      padding: 6px 10px;
      border-radius: 4px;
      margin-bottom: 8px;
    }
    .ver-row-expand-existing-label {
      display: block;
      color: var(--warning);
      font-size: 0.66rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      margin-bottom: 2px;
    }
    .ver-row-expand textarea {
      width: 100%;
      padding: 6px 8px;
      background: var(--bg-input);
      border: 1px solid var(--border-soft);
      border-radius: 6px;
      color: var(--text-primary);
      font-family: inherit;
      font-size: 0.82rem;
      resize: vertical;
      min-height: 48px;
    }
    .ver-row-expand-actions {
      display: flex; gap: 6px;
      justify-content: flex-end;
      margin-top: 6px;
    }

    /* Responsive: en móvil colapsamos monto y acciones a otra fila */
    @media (max-width: 640px) {
      .ver-row {
        grid-template-columns: 24px 84px 1fr auto;
        gap: 8px;
      }
      .ver-row-thumb-stack { width: 84px; gap: 4px; }
      .ver-row-thumb-stack .ver-row-thumb { width: 40px; height: 40px; flex: 0 0 40px; }
      .ver-row-monto { grid-column: 2 / 5; text-align: left; padding-top: 2px; }
      .ver-row-actions { grid-column: 1 / 5; justify-content: flex-end; }
    }

    /* Botón "🔍 Detalle" de cada fila de verificación. Discreto en gris
       — el énfasis visual queda en los botones de acción (✓ / ⚠). */
    .ver-row-btn.detail {
      background: transparent;
      border-color: var(--border-soft);
      color: var(--text-secondary);
      padding: 5px 8px;
    }
    /* Eliminar: se ve, pero no compite con "verificar". Contorno rojo, sin
       relleno — es la acción que menos veces se usa y la que más cuesta
       deshacer. */
    .ver-row-btn.danger {
      background: transparent;
      border-color: var(--negative);
      color: var(--negative);
      padding: 5px 8px;
    }
    .ver-row-btn.danger:hover {
      background: rgba(215,119,119,0.12);
      transform: translateY(-1px);
    }
    .ver-row-btn.detail:hover {
      border-color: var(--gold);
      color: var(--gold-bright);
      background: rgba(201,169,97,0.06);
    }

    /* Modal "Detalle de transacción" desde Verificación */
    .ver-detail-fotos {
      display: flex;
      gap: 12px;
      flex-wrap: wrap;
      margin-bottom: 16px;
    }
    .ver-detail-foto {
      flex: 1 1 220px;
      min-width: 180px;
    }
    .ver-detail-foto-label {
      font-size: 0.72rem;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.06em;
      font-weight: 600;
      margin-bottom: 6px;
    }
    .ver-detail-foto img {
      width: 100%;
      max-height: 260px;
      object-fit: cover;
      border-radius: 8px;
      border: 1px solid var(--border-soft);
      cursor: zoom-in;
      display: block;
      background: var(--bg-elevated);
    }
    .ver-detail-foto .ver-detail-foto-empty {
      width: 100%;
      min-height: 120px;
      border-radius: 8px;
      border: 1px dashed var(--border-soft);
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--text-dim);
      font-size: 0.82rem;
    }
    .ver-detail-grid {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 6px 14px;
      font-size: 0.86rem;
      align-items: baseline;
    }
    .ver-detail-grid dt {
      color: var(--text-muted);
      font-size: 0.78rem;
      font-weight: 500;
      white-space: nowrap;
    }
    .ver-detail-grid dd {
      color: var(--text-primary);
      margin: 0;
      word-break: break-word;
    }
    .ver-detail-grid dd.mono { font-variant-numeric: tabular-nums; font-weight: 600; }
    .ver-detail-grid dd.gold { color: var(--gold-bright); font-weight: 700; }
    .ver-detail-section-title {
      font-size: 0.78rem;
      color: var(--gold-bright);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      font-weight: 600;
      margin: 14px 0 8px;
      padding-bottom: 4px;
      border-bottom: 1px solid var(--border-subtle);
    }
    .ver-detail-section-title:first-child { margin-top: 0; }
    .ver-detail-obs-box {
      background: rgba(229,160,94,0.08);
      border-left: 3px solid var(--warning);
      padding: 8px 12px;
      border-radius: 6px;
      font-size: 0.86rem;
      color: var(--text-secondary);
      margin-top: 6px;
    }

    .ver-detail-vision-aviso {
      background: rgba(224, 90, 90, 0.09);
      border: 1px solid rgba(224, 90, 90, 0.35);
      border-left: 3px solid var(--negative);
      padding: 9px 12px;
      border-radius: 6px;
      font-size: 0.85rem;
      color: var(--text-secondary);
      line-height: 1.45;
      margin-bottom: 12px;
    }

    /* Veredicto de peso en el detalle: rojo si no sobró, ámbar si sobró
       demasiado, verde cuando el peso sobró como debe ser. */
    .ver-detail-peso-aviso {
      background: rgba(224, 90, 90, 0.09);
      border: 1px solid rgba(224, 90, 90, 0.35);
      border-left: 3px solid var(--negative);
      padding: 9px 12px;
      border-radius: 6px;
      font-size: 0.85rem;
      color: var(--text-secondary);
      line-height: 1.45;
      margin-bottom: 12px;
    }
    .ver-detail-peso-aviso.sano {
      background: rgba(74, 168, 108, 0.08);
      border-color: rgba(74, 168, 108, 0.32);
      border-left-color: var(--positive);
    }
    .ver-detail-peso-aviso.observacion {
      background: rgba(229, 160, 94, 0.09);
      border-color: rgba(229, 160, 94, 0.35);
      border-left-color: var(--warning);
    }

    /* Bloque "Peso del día" del reporte de cierre y de la barra de
       verificación. Mismo lenguaje de color que el aviso de arriba. */
    .peso-dia-box {
      border: 1px solid rgba(224, 90, 90, 0.35);
      border-left: 3px solid var(--negative);
      background: rgba(224, 90, 90, 0.08);
      border-radius: 6px;
      padding: 10px 12px;
      font-size: 0.86rem;
      color: var(--text-secondary);
      line-height: 1.45;
    }
    .peso-dia-box.sano {
      border-color: rgba(74, 168, 108, 0.30);
      border-left-color: var(--positive);
      background: rgba(74, 168, 108, 0.07);
    }
    .peso-dia-box.observacion {
      border-color: rgba(229, 160, 94, 0.35);
      border-left-color: var(--warning);
      background: rgba(229, 160, 94, 0.08);
    }
    .peso-dia-box.neutro {
      border-color: var(--border-subtle);
      border-left-color: var(--border-soft);
      background: var(--bg-card);
      color: var(--text-muted);
    }
    .peso-dia-box .peso-dia-titulo {
      font-weight: 700;
      color: var(--text-primary);
      margin-bottom: 3px;
    }
    .peso-dia-box .peso-dia-cifras {
      font-variant-numeric: tabular-nums;
      color: var(--text-muted);
      font-size: 0.8rem;
      margin-top: 5px;
    }
    /* ── LO QUE LEYÓ LA IA EN LA FOTO ──────────────────────────────────
       Su propio renglón, con recuadro y en el tamaño del texto normal. Antes
       iba en la misma letra gris y pequeña que el dinero del turno, pegado a
       ese renglón, y se leía como parte de él: el dato que delata una foto
       que dice 0,21 g contra un peso digitado de 1,28 g no puede ir en letra
       de pie de página (Rich, 23-oct). */
    .peso-dia-box .peso-vision {
      margin-top: 9px; padding: 8px 11px;
      border-left: 4px solid var(--border-soft);
      border-radius: 6px;
      background: rgba(255,255,255,.04);
      font-size: 1rem; line-height: 1.35;
      font-variant-numeric: tabular-nums;
    }
    .peso-dia-box .peso-vision.ok  { border-left-color: var(--positive) }
    .peso-dia-box .peso-vision.bad { border-left-color: var(--negative) }
    .peso-dia-box .peso-vision-detalle {
      font-size: 0.86rem; color: var(--text-muted); margin-top: 3px;
    }
    .peso-dia-box ul {
      margin: 7px 0 0 0;
      padding-left: 18px;
    }
    .peso-dia-box li { margin-bottom: 3px; }

    /* ═══════════════════════════════════════════════════════════════════
       PANTALLA DE BIENVENIDA — POLVO DORADO (7 s, sólo al iniciar sesión)
       ───────────────────────────────────────────────────────────────────
       El movimiento vive en un <canvas> (ver introPolvo en el JS): miles
       de partículas de polvo de oro con profundidad de campo. Aquí sólo
       está la capa, el texto y su revelado, sincronizados con la misma
       línea de tiempo:

         0   – 2.3 s  una corriente de polvo entra desde la esquina
                      inferior izquierda y fluye en diagonal hacia el centro
         2.3 – 4.6 s  el polvo se arremolina en el centro y de ahí se
                      revela el nombre: cada letra pasa de desenfocada a
                      nítida, escalonada
         4.6 – 5.8 s  el conjunto respira: el polvo flota alrededor del
                      nombre y la línea de luz termina de abrirse
         5.8 – 6.4 s  se apagan el polvo y el texto SOBRE el fondo negro,
                      que sigue opaco: la interfaz no asoma por detrás
         6.4 – 6.8 s  pausa: la pantalla se queda en negro absoluto
         6.8 – 7.3 s  recién ahí funde el negro y aparece el sistema

       El texto se revela con filter: blur → 0 y opacidad. Es lo único que
       no es transform/opacity puro, pero corre sobre 17 letras durante
       poco más de dos segundos y compensa: es justo lo que hace que
       parezca que el polvo forma las letras. ═════════════════════════ */
    /* ══ Bloqueo de pantalla por inactividad ══════════════════════════════
       Va por encima de TODO (intro incluida, 10000): si la pantalla está
       bloqueada, nada de lo que hay detrás se puede tocar ni leer con
       comodidad. El desenfoque no es adorno — evita que quien llegue lea
       datos de clientes sin la contraseña. */
    #lock-overlay {
      position: fixed;
      inset: 0;
      z-index: var(--capa-bloqueo);
      display: none;
      align-items: center;
      justify-content: center;
      padding: 20px;
      background: rgba(10, 8, 10, 0.92);
      backdrop-filter: blur(10px);
    }
    #lock-overlay.open { display: flex; }
    .lock-card {
      width: 100%;
      max-width: 380px;
      background: var(--bg-elevated);
      border: 1px solid var(--gold);
      border-radius: var(--radius);
      box-shadow: 0 24px 70px rgba(0,0,0,.65);
      padding: 28px 26px 24px;
      text-align: center;
    }
    .lock-icon {
      font-size: 30.4px;
      color: var(--gold-bright);
      line-height: 1;
      margin-bottom: 10px;
    }
    .lock-title {
      font-size: 16.8px;
      color: var(--text-primary);
      margin-bottom: 6px;
      font-weight: 600;
    }
    .lock-sub {
      font-size: .84rem;
      color: var(--text-secondary);
      line-height: 1.45;
      margin-bottom: 18px;
    }
    .lock-user {
      display: inline-block;
      font-size: .95rem;
      color: var(--gold-bright);
      font-weight: 700;
      margin-bottom: 16px;
    }
    /* Discreto: una línea que avisa, no un cartel que grita. No lleva el
       mensaje ni el nombre de nadie. */
    .lock-chat {
      display: flex; align-items: center; gap: 7px;
      margin: 0 0 16px; padding: 8px 11px;
      border: 1px solid rgba(201,169,97,.45); border-radius: 9px;
      background: rgba(201,169,97,.10);
      font-size: .86rem; color: var(--gold-bright);
      text-align: left; line-height: 1.35;
    }
    .lock-chat[hidden] { display: none }
    #lock-password {
      width: 100%;
      padding: 11px 12px;
      font-size: 16px;
      text-align: center;
      background: var(--bg-input);
      border: 1px solid var(--border-soft);
      border-radius: 8px;
      color: var(--text-primary);
      font-family: inherit;
    }
    #lock-password:focus { border-color: var(--gold); }
    #lock-error {
      min-height: 18px;
      font-size: .8rem;
      color: var(--negative);
      margin-top: 8px;
    }
    .lock-btn { width: 100%; margin-top: 12px; }
    .lock-logout {
      display: inline-block;
      margin-top: 16px;
      font-size: .78rem;
      color: var(--text-muted);
      text-decoration: underline;
      cursor: pointer;
    }
    .lock-logout:hover { color: var(--text-secondary); }

    #intro-overlay {
      position: fixed;
      inset: 0;
      z-index: var(--capa-intro);           /* sobre el aviso de versión (9999) */
      display: none;            /* mostrarIntro() lo pone en flex */
      align-items: center;
      justify-content: center;
      overflow: hidden;
      background: #000;         /* negro absoluto: el brillo lo pone el polvo */
    }
    /* La CAPA NEGRA no se toca hasta el final: aguanta opaca al 100%
       mientras se apagan el polvo y el texto (5.8–6.4 s) y durante la pausa
       (6.4–6.8 s). Sólo entonces funde. Si esta capa se desvaneciera a la
       vez que el contenido, el sistema asomaría por detrás con las letras a
       medio borrar — que es exactamente el efecto que hay que evitar.
       93.15% de 7.3 s = 6.8 s. */
    #intro-overlay.show { animation: intro-veil 7.3s linear forwards; }
    @keyframes intro-veil {
      0%, 93.15% { opacity: 1; }
      100%       { opacity: 0; }
    }

    /* El contenido (texto + halo) se va antes, y solo. El polvo hace lo
       mismo por su cuenta desde el canvas (ver salida() en el JS). */
    #intro-overlay.show .intro-content {
      animation: intro-content-out 0.6s cubic-bezier(0.4, 0, 0.6, 1) 5.8s forwards;
    }
    @keyframes intro-content-out {
      from { opacity: 1; }
      to   { opacity: 0; }
    }

    #intro-canvas {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      display: block;
    }

    /* Halo cálido detrás del nombre: aparece con el texto y respira una
       vez en el tramo final. Va debajo del texto, nunca encima. */
    .intro-content {
      position: relative;
      z-index: 1;
      text-align: center;
      padding: 0 clamp(18px, 5vw, 48px);
      max-width: min(94vw, 1000px);
    }
    .intro-content::before {
      content: '';
      position: absolute;
      left: 50%;
      top: 50%;
      width: min(150%, 900px);
      aspect-ratio: 2 / 1;
      transform: translate(-50%, -50%) scale(0.7);
      background: radial-gradient(ellipse at center, rgba(255, 194, 75, 0.20) 0%,
                  rgba(255, 194, 75, 0.07) 38%, transparent 70%);
      opacity: 0;
      pointer-events: none;
    }
    #intro-overlay.show .intro-content::before {
      animation: intro-halo 4.6s cubic-bezier(0.33, 0.7, 0.3, 1) 2.3s forwards;
    }
    @keyframes intro-halo {
      0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0.7); }
      35%  { opacity: 1;    transform: translate(-50%, -50%) scale(1); }
      70%  { opacity: 0.82; transform: translate(-50%, -50%) scale(1.06); }
      100% { opacity: 0.55; transform: translate(-50%, -50%) scale(1.1); }
    }

    /* ── Textos ──────────────────────────────────────────────────────── */
    .intro-kicker {
      font-family: var(--font-sans);
      font-size: clamp(0.6rem, 2vw, 0.88rem);
      font-weight: 500;
      letter-spacing: 0.42em;
      text-indent: 0.42em;      /* compensa el espaciado sobrante a la derecha */
      text-transform: uppercase;
      color: #e8d5a8;
      opacity: 0;
    }
    #intro-overlay.show .intro-kicker {
      animation: intro-soft-in 1.5s cubic-bezier(0.22, 0.8, 0.3, 1) 2s forwards;
    }
    @keyframes intro-soft-in {
      from { opacity: 0; filter: blur(8px); transform: translate3d(0, 8px, 0); }
      to   { opacity: 1; filter: blur(0);   transform: translate3d(0, 0, 0); }
    }

    .intro-title {
      /* La serif del logo, en versales y con mucho aire entre letras:
         cartel de película, no encabezado de sección. */
      font-family: var(--font-serif);
      font-style: normal;
      font-weight: 700;
      font-size: clamp(1.6rem, 6.6vw, 4.1rem);
      line-height: 1.12;
      letter-spacing: 0.14em;
      text-indent: 0.14em;
      text-transform: uppercase;
      color: #ffe9b0;
      text-shadow: 0 0 26px rgba(255, 194, 75, 0.55), 0 0 70px rgba(255, 165, 0, 0.28);
      margin: clamp(14px, 2.4vw, 22px) 0 0;
    }
    .intro-word { display: inline-block; white-space: nowrap; }
    .intro-letter {
      display: inline-block;
      opacity: 0;
      filter: blur(14px);
      transform: translate3d(0, 14px, 0) scale(1.08);
      will-change: filter, opacity, transform;
    }
    /* El retardo de cada letra lo pone el JS (55 ms de diferencia), de
       modo que el nombre se va condensando de izquierda a derecha. */
    #intro-overlay.show .intro-letter {
      animation: intro-letter-in 1.25s cubic-bezier(0.2, 0.75, 0.25, 1) both;
    }
    @keyframes intro-letter-in {
      to { opacity: 1; filter: blur(0); transform: translate3d(0, 0, 0) scale(1); }
    }

    .intro-user {
      font-family: var(--font-sans);
      font-size: clamp(0.7rem, 2.2vw, 0.9rem);
      font-weight: 500;
      letter-spacing: 0.24em;
      color: rgba(255, 233, 176, 0.72);
      margin-top: clamp(14px, 2.2vw, 20px);
      opacity: 0;
      min-height: 1.2em;        /* reserva el alto aunque no haya nombre */
    }
    #intro-overlay.show .intro-user {
      animation: intro-soft-in 1.6s cubic-bezier(0.22, 0.8, 0.3, 1) 4s forwards;
    }

    /* Una fina línea de luz bajo el nombre, como un reflejo del polvo. */
    .intro-underline {
      width: min(62%, 460px);
      height: 1px;
      margin: clamp(16px, 2.4vw, 24px) auto 0;
      background: linear-gradient(90deg, transparent 0%, rgba(255, 194, 75, 0.85) 50%, transparent 100%);
      box-shadow: 0 0 14px rgba(255, 194, 75, 0.5);
      opacity: 0;
      transform: scaleX(0.2);
    }
    #intro-overlay.show .intro-underline {
      animation: intro-underline-in 2s cubic-bezier(0.16, 1, 0.3, 1) 3.6s forwards;
    }
    @keyframes intro-underline-in {
      to { opacity: 1; transform: scaleX(1); }
    }

    /* Sin movimiento: la misma portada, quieta, los mismos 7.3 s, y el
       corte al final es seco en vez de fundido. El canvas pinta un solo
       fotograma de polvo (ver introPolvo). */
    @media (prefers-reduced-motion: reduce) {
      #intro-overlay.show,
      #intro-overlay.show .intro-content,
      #intro-overlay.show .intro-content::before,
      #intro-overlay.show .intro-kicker,
      #intro-overlay.show .intro-letter,
      #intro-overlay.show .intro-underline,
      #intro-overlay.show .intro-user {
        animation: none !important;
        opacity: 1;
        filter: none;
        transform: none;
      }
      #intro-overlay.show .intro-content::before {
        opacity: 0.8;
        transform: translate(-50%, -50%) scale(1);
      }
    }

    /* ── "Recordar mi usuario" (pantalla de login) ───────────────────── */
    .login-recordar {
      display: flex;
      align-items: flex-start;
      gap: 10px;
      margin: 14px 0 4px;
      cursor: pointer;
      user-select: none;
      font-size: 0.86rem;
      color: var(--text-secondary);
      letter-spacing: 0.02em;
    }
    .login-recordar input {
      width: 18px;
      height: 18px;
      margin-top: 1px;
      flex-shrink: 0;
      accent-color: var(--gold);
      cursor: pointer;
    }
    .login-recordar small {
      display: block;
      margin-top: 2px;
      font-size: 0.74rem;
      color: var(--text-muted);
      letter-spacing: 0.03em;
    }
    .login-recordar:hover { color: var(--text-primary); }

    /* ═══════════════════════════════════════════════════════════════════
       RECIBO TÉRMICO 80 mm
       ───────────────────────────────────────────────────────────────────
       Se imprime por el navegador, sin drivers ni librerías: el rollo se
       instala como impresora normal de Windows y esto le manda una página
       del ancho exacto del papel.

       La hoja mide 80 mm de ancho y el largo exacto del recibo: se mide
       antes de imprimir y el tamaño lo pone _fijarHojaRecibo (en el JS), así
       el rollo corta donde termina. Márgenes en 0 porque el margen lo pone
       el propio papel; el respiro va en el padding de #recibo-print.

       Lo que manda es la IMPRESORA, no el CSS. Con el driver "Generic /
       Text Only" Chrome no le pasa un dibujo sino sólo el texto, renglón por
       renglón (ver "Maquetado" en el JS): el recibo llega ya armado como
       texto de 48 columnas, centrado con espacios y con separadores de
       guiones. Aquí sólo se muestra en monoespaciada con la geometría de la
       3nStar, para que la vista previa sea el papel:
         · 72 mm de zona escrita / 48 columnas = 1.5 mm por carácter, y
           Courier avanza 0.6 em → letra de 2.5 mm
         · renglón de la impresora: 3.75 mm → interlineado 1.5
         · nada de negritas, tamaños ni bordes: el driver no los manda, y la
           vista previa no puede prometer lo que el papel no trae

       Al imprimir se ocultan TODOS los hermanos del recibo (la app entera,
       modales incluidos) en vez de esconder cosas una por una: si mañana se
       agrega una sección nueva, no se cuela en el papel.

       Negro sobre blanco y sin fondos. ════════════════════════════════════ */
    #recibo-print { display: none; }

    /* El formato del papel vive FUERA de @media print a propósito: así vale
       también en pantalla —donde el recibo sigue oculto— y se puede MEDIR
       antes de imprimir para pedir una hoja del largo justo. Todas las
       reglas cuelgan de #recibo-print: no alcanzan nada fuera del recibo. */
    #recibo-print {
      width: 80mm;
      margin: 0;
      padding: 3mm 4mm 0;     /* el espacio para cortar va en el propio texto */
      background: #fff;
      color: #000;
      -webkit-print-color-adjust: exact;
      print-color-adjust: exact;
    }
    /* Mientras se mide: maquetado, pero fuera de la vista y sin pintarse. */
    #recibo-print.rc-midiendo {
      display: block;
      position: absolute;
      left: -10000px;
      top: 0;
      visibility: hidden;
    }

    #recibo-print .rc-papel {
      margin: 0;
      font-family: 'Courier New', Courier, monospace;
      font-size: 2.5mm;
      font-weight: 400;
      line-height: 1.5;
      letter-spacing: 0;
      white-space: pre;       /* los espacios del centrado son parte del texto */
    }

    @media print {
      /* Sin márgenes para todo lo que se imprime, como ya estaba. El TAMAÑO
         de la hoja no va aquí: lo pone _fijarHojaRecibo sólo mientras se
         imprime un recibo (si fuera fijo, los informes saldrían a 80 mm). */
      @page { margin: 0; }

      html, body {
        height: auto !important;
        overflow: visible !important;
        background: #fff !important;
      }
      body.imprimiendo-recibo > *:not(#recibo-print) { display: none !important; }

      /* El resplandor dorado del fondo es un ::before de body, fijo y a
         pantalla completa. Un pseudo-elemento no es un hijo, así que la
         regla de arriba no lo alcanza: en papel quedaba como una capa
         encima del recibo y la hoja salía EN BLANCO. */
      body.imprimiendo-recibo::before,
      body.imprimiendo-recibo::after { display: none !important; }

      body.imprimiendo-recibo #recibo-print { display: block !important; }

      #recibo-print * { color: #000 !important; background: transparent !important; }
    }

    /* Nada de esto es información: si el equipo o el sistema pide menos
       movimiento, se apaga todo el movimiento y queda el color. */
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
      }
    }

    /* ═══════════════════════════════════════════════════════════════════
       LA LIBRETA — capa visual (fiel al diseño aprobado)
       ═══════════════════════════════════════════════════════════════════

       Copia del diseño de referencia aprobado: escritorio negro con malla
       dorada, barra superior con la marca, siete pestañas repartidas a lo
       ancho colgando de la libreta, y la hoja abierta con su
       pila de hojas detrás y los cantos de colores a la derecha.

       Esta capa va al final del <style> para ganar por cascada sobre el
       chasis heredado. Lo que hace, además de vestir el chasis nuevo, es
       re-declarar los tokens que ya usaban las ~4.000 líneas de estilo de
       arriba (--bg-card, --text-primary, --border-subtle…): así las
       pantallas que todavía no se han migrado una por una ya heredan la
       paleta de la referencia en vez de quedar con el traje viejo.

       El tema claro sólo vuelve a declarar variables. Ninguna regla de
       maqueta se escribe dos veces.
    ══════════════════════════════════════════════════════════════════════ */

    :root{
      /* Paleta de la referencia, tal cual */
      --n0:#020204; --n1:#0b0a06; --n2:#100e09; --n3:#181408; --pagina:#0e0c07; --pagina2:#13110a;
      --oro:#f6c945; --oro-claro:#ffe291; --oro-med:#c9a227; --oro-dim:#41340f; --linea:#241d09;
      --texto:#efe9d8; --gris:#918e84; --gris-2:#615e56;
      --verde:#3ddc84; --rojo:#ef5350; --cian:#38dde4;
      --glow:rgba(246,201,69,.5); --glow-suave:rgba(246,201,69,.12);
      --sombra:0 30px 70px -30px rgba(0,0,0,.95);

      /* Colores de cada pestaña (los de la referencia) */
      --c-inicio:#f6c945; --c-registrar:#3ddc84; --c-historial:#38dde4;
      --c-internet:#f472b6; --c-cuentas:#a78bfa; --c-cierre:#fb923c; --c-admin:#f87171;

      /* Una sola letra para todo: Times New Roman, ya instalada. */
      --font-serif:'Times New Roman', Times, 'Liberation Serif', serif;
      --font-sans: 'Times New Roman', Times, 'Liberation Serif', serif;

      /* ── Puente con el chasis heredado ─────────────────────────────
         Los mismos nombres de siempre, apuntando a la paleta nueva. */
      --bg-base:        var(--pagina);
      --bg-elevated:    var(--n3);
      --bg-card:        var(--n2);
      --bg-input:       var(--n1);
      --bg-overlay:     rgba(2,2,4,.86);
      --bg-gold-start:  #2c220e;
      --bg-gold-end:    #40310f;
      --bg-gold-grad:   linear-gradient(135deg, #2c220e 0%, #40310f 100%);
      --oro-macizo:     linear-gradient(170deg, var(--oro-claro), var(--oro) 60%);

      --border-subtle:  var(--linea);
      --border-soft:    var(--oro-dim);
      --border-strong:  var(--oro-med);
      --border-accent:  var(--oro-med);
      --border-gold:    var(--oro-med);

      --gold:           var(--oro);
      --gold-bright:    var(--oro-claro);
      --gold-dim:       var(--oro-med);
      --gold-light:     var(--oro-claro);
      --gold-dark:      var(--oro-med);
      --text-on-gold:   #141001;

      --text-primary:   var(--texto);
      --text-secondary: var(--texto);
      --text-muted:     var(--gris);
      --text-dim:       var(--gris-2);
      --text-dark:      var(--texto);
      --text-med:       var(--gris);
      --white:          var(--n2);
      --border:         var(--linea);

      --positive:       var(--verde);
      --positive-bg:    rgba(61,220,132,.12);
      --negative:       var(--rojo);
      --negative-bg:    rgba(239,83,80,.12);
      --warning:        var(--oro);
      --cyan-accent:    var(--cian);
      --rose:           var(--oro-med);
      --rose-light:     var(--n1);
      --rose-mid:       var(--n3);
      --rose-deep:      var(--oro);
      --rose-med:       var(--oro);

      --radius-sm:9px; --radius-md:14px; --radius-lg:16px; --radius:14px;
      --shadow-card:0 20px 50px -26px rgba(0,0,0,.85), inset 0 1px 0 var(--glow-suave);
      --shadow:var(--shadow-card); --shadow-lg:var(--shadow-card);
      --shadow-gold:0 0 36px -14px var(--glow);
    }

    /* El tema claro es de papel, no de pantalla: el escritorio es una mesa de
       madera clara (--n0, beige) y encima van las hojas, en gris claro apenas
       teñido. Antes las hojas eran casi blanco puro y golpeaban la vista a las
       horas de mostrador.

       Las medidas:
         · las hojas y pestañas quedan con un 2% de saturación —gris de
           verdad, no crema— y el escritorio es 23% más oscuro que ellas, así
           que papel y mesa se distinguen sin esfuerzo;
         · texto, grises, verde, rojo y cian pasan de 4,5:1 sobre las tres
           superficies donde pueden caer: hoja, pestaña y escritorio.

       El DORADO es la excepción, y es a propósito: es el color de los botones
       de siempre (#7a5a00 → #9c7500) y se devolvió tal cual se pidió. Como
       esas dos variables también se usan para texto suelto (la marca, el
       botón de tema), ese texto dorado queda en 3,6:1 sobre la hoja y 2,8:1
       sobre el escritorio. Queda escrito acá para que nadie lo "arregle" sin
       saber que cambiaría el color de los botones.

       Los dos grises son dos escalones distintos (7,4:1 y 6,1:1 sobre la
       hoja): si se igualaran, se perdería la diferencia entre "apagado" y
       "tenue", que es información. */
    [data-tema="claro"]{
      --n0:#ddd3b9; --n1:#e9e8e4; --n2:#eeedea; --n3:#e4e3df; --pagina:#f0efec; --pagina2:#eae9e6;
      --oro:#9c7500; --oro-claro:#7a5a00; --oro-med:#634908; --oro-dim:#c4b184; --linea:#ded3b6;
      --texto:#262214; --gris:#4f4c3e; --gris-2:#5c5848;
      --verde:#145c33; --rojo:#a8221b; --cian:#00656e;
      --glow:rgba(110,80,0,.28); --glow-suave:rgba(110,80,0,.07);
      --sombra:0 24px 55px -28px rgba(80,62,18,.42);

      --text-on-gold:#fff;
      /* Con la luz encendida el tinte es crema; encima, texto oscuro. */
      --bg-gold-start:#f0e6cd;
      --bg-gold-end:#e2d5b2;
      --bg-gold-grad:linear-gradient(135deg, #f0e6cd 0%, #e2d5b2 100%);
      --positive-bg:rgba(20,92,51,.12);
      --negative-bg:rgba(168,34,27,.10);
      --shadow-card:0 14px 34px -22px rgba(80,62,18,.5), inset 0 1px 0 rgba(255,252,240,.55);
    }

    /* ═══════════════════════════════════════════════════════════════════
       EL ESCRITORIO
    ══════════════════════════════════════════════════════════════════════ */
    *, *::before, *::after{ box-sizing:border-box }
    /* La raíz manda sobre todo lo escrito en rem, que en este archivo es
       exactamente el texto de cuerpo: descripciones, notas y subtítulos.
       Subirla de 16 a 18 px es el único sitio donde se toca su tamaño. */
    html{ height:auto; overflow:visible; font-size:18px }
    body{
      display:block; min-height:100vh; height:auto;
      overflow-x:hidden; overflow-y:auto;
      background:var(--n0); color:var(--texto);
      font-family:var(--font-sans); font-size:18px;
      transition:background .4s;
    }
    body::before{
      content:''; position:fixed; inset:0; z-index:0; pointer-events:none;
      background:radial-gradient(1100px 520px at 50% -12%, var(--glow-suave), transparent 60%);
    }
    .malla{
      position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.05;
      background-image:linear-gradient(var(--oro) 1px, transparent 1px), linear-gradient(90deg, var(--oro) 1px, transparent 1px);
      background-size:72px 72px;
      mask-image:radial-gradient(ellipse 80% 45% at 50% 0%, #000, transparent 90%);
      -webkit-mask-image:radial-gradient(ellipse 80% 45% at 50% 0%, #000, transparent 90%);
    }
    body.unauthed .malla{ display:none }

    /* #app es el "wrap" de la referencia: la app entera centrada. */
    #app{
      position:relative; z-index:1;
      max-width:1220px; margin:0 auto; padding:0 24px 60px;
      display:block; height:auto; overflow:visible;
    }
    ::-webkit-scrollbar{ width:9px; height:9px }
    ::-webkit-scrollbar-track{ background:transparent }
    ::-webkit-scrollbar-thumb{ background:var(--oro-dim); border-radius:99px }
    ::-webkit-scrollbar-thumb:hover{ background:var(--oro-med) }

    /* ═══════════════════════════════════════════════════════════════════
       BARRA SUPERIOR DEL ESCRITORIO (fuera de la hoja)
    ══════════════════════════════════════════════════════════════════════ */
    .top{ display:flex; align-items:center; gap:20px; padding:18px 4px 0 }
    .marca{ font-style:italic; font-size:26px; line-height:1.05; white-space:nowrap; font-weight:bold; color:var(--texto) }
    .marca em{ color:var(--oro); font-style:italic }
    .marca small{ font-style:normal; font-weight:normal; font-size:9px; letter-spacing:5px; color:var(--gris-2); display:block; margin-top:3px }

    /* El buscador global de siempre, con el traje de la referencia. */
    #bg-wrap{ position:relative; flex:1; max-width:330px; min-width:150px; margin:0 }
    #bg-input{
      width:100%; border:1px solid var(--oro-dim); border-radius:10px;
      padding:10px 34px 10px 34px; background:var(--glow-suave); color:var(--texto);
      font-family:var(--font-sans); font-size:14px; font-style:italic;
    }
    #bg-input::placeholder{ color:var(--gris-2); font-style:italic }
    #bg-input:focus{ border-color:var(--oro-med); box-shadow:0 0 18px -8px var(--glow) }
    #bg-icon{ position:absolute; left:11px; top:50%; transform:translateY(-50%); width:15px; height:15px; color:var(--oro-med); pointer-events:none }
    #bg-clear{ position:absolute; right:8px; top:50%; transform:translateY(-50%); background:none; border:none; color:var(--gris); cursor:pointer; font-size:13px }
    /* El panel de resultados conserva su tamaño de siempre (cabe una
       transacción entera por línea); aquí sólo cambia de traje. */
    #bg-panel{ background:var(--n2); border:1px solid var(--oro-dim); border-radius:12px; box-shadow:var(--sombra) }

    .util{ margin-left:auto; display:flex; gap:16px; align-items:center; font-size:11px; letter-spacing:2px; color:var(--gris); white-space:nowrap }
    .dot{ width:5px; height:5px; border-radius:50%; background:var(--verde); box-shadow:0 0 8px var(--verde); display:inline-block; margin-right:6px; animation:pulso 2.6s infinite }
    @keyframes pulso{ 0%,100%{opacity:1} 50%{opacity:.3} }

    .tema-btn{
      cursor:pointer; border:1px solid var(--oro-dim); background:var(--glow-suave); color:var(--oro);
      border-radius:20px; padding:7px 16px; font-family:inherit; font-size:11px; letter-spacing:2px;
      white-space:nowrap; transition:box-shadow .25s, color .25s;
    }
    .tema-btn:hover{ box-shadow:0 0 16px -6px var(--glow); color:var(--oro-claro) }
    [data-tema="claro"] .tema-btn:hover{ color:var(--oro-med) }

    /* Sesión: avatar + nombre + rol, con su menú. */
    .sesion{ position:relative; cursor:pointer }
    .sesion .pill{
      display:flex; align-items:center; gap:10px; border:1px solid var(--oro-med); border-radius:24px;
      padding:6px 16px 6px 7px; background:var(--glow-suave); transition:all .25s;
    }
    .sesion:hover .pill{ box-shadow:0 0 18px -6px var(--glow) }
    .sesion .ava{
      width:30px; height:30px; border-radius:50%; border:1px solid var(--oro-med);
      display:flex; align-items:center; justify-content:center;
      font-size:15px; font-style:italic; color:var(--oro); background:var(--n2); text-transform:uppercase;
    }
    .sesion .qn{ font-size:13px; line-height:1.15; text-align:left }
    .sesion .qn b{ display:block; color:var(--texto) }
    .sesion .qn small{ font-size:10px; color:var(--oro-med); letter-spacing:2px; text-transform:uppercase }
    .sesion .menu-s{
      position:absolute; right:0; top:calc(100% + 8px); min-width:210px;
      border:1px solid var(--oro-dim); border-radius:12px; background:var(--n2);
      box-shadow:var(--sombra); padding:7px;
      opacity:0; pointer-events:none; transform:translateY(-6px); transition:all .3s; z-index:99;
    }
    /* El menú se abre con un CLIC y se queda abierto: lo cierran un clic
       fuera, Escape, o elegir una opción. Antes lo abría :hover, y como la
       clase '.abierto' la pone el JS en el MENÚ (no en '.sesion', que era lo
       que este selector miraba), el hover era lo ÚNICO que lo mostraba: el
       menú vivía mientras el puntero o el dedo estaban encima y se cerraba
       al soltar, sin darle tiempo a nadie de llegar a "Cerrar sesión". */
    .sesion .menu-s.abierto{ opacity:1; pointer-events:auto; transform:none }
    .menu-s button{
      display:block; width:100%; text-align:left; background:none; border:none; cursor:pointer;
      padding:10px 14px; border-radius:8px; font-family:var(--font-sans); font-size:14px;
      color:var(--gris); transition:all .2s;
    }
    .menu-s button:hover{ color:var(--oro); background:var(--glow-suave) }
    .menu-s button.rojo:hover{ color:var(--rojo) }

    /* ── LA CAMPANITA ─────────────────────────────────────────────────
       Vive entre los botones de la barra y la sesión, y se viste como
       ellos: círculo con filo dorado sobre el mismo fondo tenue. Redonda y
       sólo con el símbolo, porque al lado del pill de la sesión dos cosas
       con texto se pelean — y porque el globito tiene que ser lo único
       que llame la atención.

       Es el HISTORIAL. El muro de Inicio sigue donde estaba, grande y en
       medio, y el cartel rojo del mostrador no se toca: esto es para
       después, no en lugar de ellos. */
    .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;
    }
    .campana{ position:relative }
    .campana-btn{
      position:relative; cursor:pointer; display:flex; align-items:center; justify-content:center;
      width:40px; height:40px; border-radius:50%;
      border:1px solid var(--oro-dim); background:var(--glow-suave); color:var(--oro);
      transition:box-shadow .25s, color .25s;
    }
    .campana-btn svg{ width:19px; height:19px }
    .campana-btn:hover{ box-shadow:0 0 16px -6px var(--glow); color:var(--oro-claro) }
    [data-tema="claro"] .campana-btn:hover{ color:var(--oro-med) }
    .campana-btn.tiene-avisos{ border-color:var(--oro-med) }
    /* El globito: rojo, y sólo cuando hay algo sin ver. Un número que está
       siempre puesto se deja de mirar. */
    .campana-globo{
      position:absolute; top:-3px; right:-3px; min-width:18px; height:18px; padding:0 5px;
      border-radius:9px; background:var(--negative); color:#fff;
      font-family:var(--font-sans); font-size:11px; font-weight:700; line-height:18px;
      text-align:center; letter-spacing:0; box-shadow:0 0 0 2px var(--n1);
    }
    .campana-panel{
      position:absolute; right:0; top:calc(100% + 8px); width:400px; max-width:92vw;
      border:1px solid var(--oro-dim); border-radius:12px; background:var(--n2);
      box-shadow:var(--sombra); z-index:120;
      opacity:0; pointer-events:none; transform:translateY(-6px); transition:all .3s;
      display:flex; flex-direction:column; max-height:min(70vh, 560px);
    }
    .campana-panel.abierto{ opacity:1; pointer-events:auto; transform:none }
    .campana-cab{
      display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
      padding:12px 14px 10px; border-bottom:1px solid var(--oro-dim);
    }
    .campana-cab b{ font-family:var(--font-serif); font-style:italic; font-size:17px; color:var(--texto); letter-spacing:0 }
    .campana-cab #campana-resumen{ font-size:12px; color:var(--gris); letter-spacing:1px }
    /* Las dos acciones de la cabecera, juntas y a la derecha: marcar todo
       como visto y la papelera. Van en un grupo para que al esconderse una
       la otra no se mueva de sitio. */
    .campana-cab-acc{
      margin-left:auto; display:flex; align-items:center; gap:11px; flex-shrink:0;
    }
    .campana-todos{
      cursor:pointer; background:none; border:none; padding:0;
      font-family:var(--font-sans); font-size:12px; color:var(--oro-med); letter-spacing:0;
      text-decoration:underline; text-underline-offset:3px;
    }
    .campana-todos:hover{ color:var(--oro-claro) }
    .campana-todos[hidden]{ display:none }
    /* La papelera. Gris mientras no la toquen: borrar no es la acción
       principal de este panel y no tiene por qué llamar la atención. Se
       pone roja al pasar por encima, que es lo que va a hacer. */
    .campana-borrar{
      cursor:pointer; background:none; border:none; padding:2px;
      display:flex; align-items:center; color:var(--gris);
      transition:color .2s; border-radius:5px;
    }
    .campana-borrar svg{ width:15px; height:15px }
    .campana-borrar:hover{ color:var(--negative) }
    .campana-borrar[hidden]{ display:none }
    /* La pregunta. Dentro del panel, no un cartel del navegador: así se lee
       al lado de la lista que se va a borrar, dice cuántos son y recuerda
       que los sin ver se quedan. */
    .campana-confirma{
      padding:11px 14px; border-bottom:1px solid var(--oro-dim);
      background:var(--glow-suave); font-size:12.5px; color:var(--texto);
      letter-spacing:0; line-height:1.4;
    }
    .campana-confirma[hidden]{ display:none }
    .campana-confirma .cc-aviso{ color:var(--gris); display:block; margin-top:3px }
    .campana-confirma .cc-btns{ display:flex; gap:8px; margin-top:9px; flex-wrap:wrap }
    /* El recorrido va DENTRO del panel: la página de detrás no se mueve. */
    .campana-lista{ overflow-y:auto; padding:8px; flex:1; min-height:60px }
    .campana-pie{
      padding:9px 14px; border-top:1px solid var(--oro-dim);
      font-size:11.5px; color:var(--gris-2); letter-spacing:0; line-height:1.35;
    }
    /* Cada aviso. El filo de color lo pone el JS según el tipo, igual que en
       el muro, para que un aviso sea del mismo color en los dos sitios. */
    .campana-item{
      border:1px solid var(--oro-dim); border-left-width:3px; border-radius:10px;
      padding:10px 12px; margin-bottom:8px; background:transparent;
    }
    .campana-item:last-child{ margin-bottom:0 }
    .campana-item.sin-ver{ background:var(--glow-suave) }
    .campana-item .ci-tit{
      font-family:var(--font-sans); font-size:14px; font-weight:700; color:var(--texto);
      line-height:1.3; letter-spacing:0;
    }
    .campana-item .ci-cuando{
      font-size:11.5px; color:var(--gris-2); letter-spacing:0; margin-top:3px;
    }
    .campana-item .ci-punto{
      display:inline-block; width:7px; height:7px; border-radius:50%;
      background:var(--negative); margin-right:6px; vertical-align:middle;
    }
    .campana-item .ci-det{
      font-size:13px; color:var(--text-secondary); line-height:1.4;
      margin-top:6px; letter-spacing:0;
    }
    .campana-item .ci-det div{ margin-bottom:2px }
    /* Cerrado: sólo el titular y la fecha. Se abre al pulsarlo. */
    .campana-item .ci-det[hidden]{ display:none }
    .campana-item .ci-cab{ cursor:pointer }
    .campana-item .ci-acciones{ margin-top:9px; display:flex; gap:7px; flex-wrap:wrap }
    /* El `display:flex` de arriba le gana al display:none que el navegador
       le da a [hidden], así que hay que decirlo a mano: sin esto, un aviso
       ya visto enseñaba sus botones aunque estuviera plegado. */
    .campana-item .ci-acciones[hidden]{ display:none }
    .campana-vacio{ padding:26px 14px; text-align:center; color:var(--gris-2); font-size:13.5px; letter-spacing:0 }

    /* ═══════════════════════════════════════════════════════════════════
       LA LIBRETA
    ══════════════════════════════════════════════════════════════════════ */
    .libreta{ position:relative; margin-top:84px; min-height:640px }

    .hoja{ --c:var(--oro); position:absolute; inset:0; z-index:1 }
    .hoja.on{ position:relative; z-index:6; animation:traer .6s cubic-bezier(.2,.85,.25,1) }
    /* la hoja ENTERA (con su pestaña pegada) viene del fondo hacia adelante */
    @keyframes traer{
      from{ opacity:0; transform:scale(.93) translateY(18px); filter:blur(3px) }
      60%{ filter:blur(0) }
      to{ opacity:1; transform:none }
    }
    .hoja:not(.on) .cuerpo{ opacity:0; pointer-events:none }
    .hoja:not(.on){ pointer-events:none }
    .hoja:not(.on) .pestana{ pointer-events:auto }

    /* Pestañas: a lo ancho de toda la página, colgando de la hoja. */
    .pestana{
      position:absolute; top:-56px; height:57px; width:12.5%; min-width:0; padding:10px 8px 0;
      border:1px solid var(--linea); border-bottom:none; border-radius:13px 13px 0 0;
      background:linear-gradient(180deg, var(--n3), var(--pagina2));
      box-shadow:inset 0 3px 0 color-mix(in srgb, var(--c) 55%, transparent), 0 -8px 22px -12px rgba(0,0,0,.7);
      font-size:clamp(9px, 1.05vw, 12px); letter-spacing:clamp(0px, .16vw, 2px); color:var(--gris);
      text-align:center; cursor:pointer; transition:color .3s, background .3s, box-shadow .3s, top .3s, height .3s; z-index:2;
      font-family:var(--font-sans);
      white-space:nowrap; overflow:hidden;
    }
    .pestana .mini{ display:block; font-size:clamp(15px, 1.6vw, 19px); font-style:italic; color:var(--c); opacity:.85; margin-bottom:3px }
    .pestana:hover{ transform:translateY(-5px); color:var(--texto) }
    .pestana .badge{
      position:absolute; top:6px; right:7px; font-size:11px; font-weight:bold; color:#141001;
      background:var(--c); border-radius:20px; padding:1px 7px; min-width:20px;
      box-shadow:0 0 10px color-mix(in srgb, var(--c) 60%, transparent); display:none;
    }
    .pestana.tiene-aviso .badge{ display:block }
    [data-tema="claro"] .pestana .badge{ color:var(--text-on-gold) }

    /* Pestaña de la hoja abierta: sube con su hoja, fundidas en una pieza. */
    .hoja.on .pestana{
      top:-70px; height:71px; padding-top:16px;
      color:var(--c);
      border-color:color-mix(in srgb, var(--c) 60%, transparent); border-bottom:none;
      background:linear-gradient(180deg, var(--n3) 0%, var(--pagina) 100%);
      box-shadow:inset 0 3px 0 var(--c), 0 -12px 32px -12px color-mix(in srgb, var(--c) 45%, transparent);
    }
    .hoja.on .pestana .mini{ opacity:1; text-shadow:0 0 16px color-mix(in srgb, var(--c) 60%, transparent) }
    .hoja.on .pestana::after{ content:''; position:absolute; left:0; right:0; bottom:-2px; height:4px; background:var(--pagina) }

    .cuerpo{
      position:relative; border:1px solid color-mix(in srgb, var(--c) 55%, transparent);
      border-radius:16px; min-height:600px;
      background:linear-gradient(170deg, var(--pagina2) 0%, var(--pagina) 22%);
      box-shadow:var(--sombra), 0 0 55px -22px color-mix(in srgb, var(--c) 45%, transparent), inset 0 1px 0 var(--glow-suave);
      padding:32px 36px 44px 48px;
    }
    .hoja.on .cuerpo::after{
      content:''; position:absolute; z-index:-1; left:8px; right:-6px; top:10px; bottom:-6px;
      border-radius:16px; background:var(--n2); border:1px solid var(--linea);
      box-shadow:6px 8px 0 -2px var(--n1), 6px 8px 0 -1px var(--linea), 12px 16px 0 -5px var(--n0), 12px 16px 0 -4px var(--linea);
    }
    /* Aquí iba la espiral: ocho anillos pegados al borde izquierdo de la
       LIBRETA, por debajo de la hoja abierta (z-index 2 contra 6). La hoja
       los tapaba siempre, así que nunca se veían… salvo al cambiar de
       pestaña: la hoja entra encogida y transparente ("traer") y los anillos
       asomaban como 3-5 huecos en el borde izquierdo —más o menos según lo
       alta que fuera la página—. Se quitó: la hoja terminada se ve igual. */
    .cantos{
      position:absolute; right:-2px; top:26px; bottom:26px; width:7px; border-radius:4px; opacity:.9; z-index:2; pointer-events:none;
      background:linear-gradient(180deg,
        #f6c945 0% 14%, #3ddc84 14% 28%, #38dde4 28% 42%, #f472b6 42% 57%,
        #a78bfa 57% 71%, #fb923c 71% 85%, #f87171 85% 100%);
      box-shadow:-2px 0 8px rgba(0,0,0,.5);
    }
    .cantos::before{ content:''; position:absolute; inset:0; border-radius:4px;
      background:repeating-linear-gradient(180deg, transparent 0 3px, rgba(0,0,0,.35) 3px 4px) }

    /* ═══════════════════════════════════════════════════════════════════
       DENTRO DE LA HOJA
    ══════════════════════════════════════════════════════════════════════ */
    /* Índice de la hoja: los destinos de siempre, con el traje nuevo. */
    .subnav{
      display:none; flex-wrap:wrap; align-items:center;
      column-gap:8px; row-gap:10px;
      margin:0 0 22px; max-width:100%;
    }
    .subnav.abierta{ display:flex }
    .subnav.una-sola{ display:none }
    .nav-item{
      display:inline-flex; align-items:center; gap:7px; margin:0;
      font-family:var(--font-sans); font-size:13px; padding:7px 17px; border-radius:20px;
      border:1px solid var(--linea); background:transparent; color:var(--gris);
      cursor:pointer; transition:all .25s;
    }
    .nav-item{ max-width:100% }
    .nav-item:hover{ color:var(--texto); border-color:var(--oro-dim); background:var(--glow-suave) }
    .nav-item.active{
      color:var(--c); border-color:color-mix(in srgb, var(--c) 60%, transparent);
      background:var(--glow-suave); box-shadow:0 0 14px -6px color-mix(in srgb, var(--c) 50%, transparent);
    }
    .nav-icon{ font-size:13px; width:auto; color:inherit; opacity:.85 }
    .nav-badge{
      display:none; min-width:19px; padding:1px 7px; border-radius:20px;
      background:var(--c); color:#141001; font-size:11px; font-weight:bold; text-align:center;
    }
    [data-tema="claro"] .nav-badge{ color:var(--text-on-gold) }

    /* Secciones: sólo se ve la activa, con la aparición de la referencia. */
    .section{ display:none }
    .section.active{ display:block; animation:traer .4s cubic-bezier(.2,.85,.25,1) }

    /* Títulos: el chasis los escribe con .section-title / .section-sub /
       .gold-line; la referencia los llama .titulo / .subt / .raya. */
    .section-title, .titulo{
      font-family:var(--font-serif); font-style:italic; font-size:30px; font-weight:bold;
      color:var(--texto); margin:0 0 0; letter-spacing:0;
    }
    .section-sub{ font-size:16px; color:var(--gris); margin:3px 0 0; font-style:italic }
    .gold-line, .raya{
      height:2px; width:160px; border-radius:2px; border:none;
      background:linear-gradient(90deg, var(--c), transparent);
      box-shadow:0 0 10px color-mix(in srgb, var(--c) 55%, transparent);
      margin:12px 0 22px;
    }

    /* Tarjetas */
    .card, .kpi-card{
      border-radius:14px; border:1px solid var(--linea); position:relative; overflow:hidden;
      background:linear-gradient(165deg, var(--n3), var(--n1) 70%);
      box-shadow:0 20px 50px -26px rgba(0,0,0,.85), inset 0 1px 0 var(--glow-suave);
      transition:all .4s cubic-bezier(.2,.8,.2,1);
      margin-bottom:14px;
    }
    .card:hover, .kpi-card:hover{
      transform:translateY(-3px); border-color:var(--oro-dim);
      box-shadow:0 26px 60px -26px rgba(0,0,0,.9), 0 0 36px -14px var(--glow);
    }
    .card-header{ padding:16px 20px; border-bottom:1px solid var(--linea) }
    .card-title{ font-family:var(--font-serif); font-style:italic; font-size:18px; font-weight:bold; color:var(--texto) }
    .card-body{ padding:20px }
    .eti{ font-size:11px; letter-spacing:3px; color:var(--oro-med); text-transform:uppercase }
    .cifra{
      font-weight:bold; font-variant-numeric:tabular-nums;
      background:linear-gradient(176deg, var(--oro-claro) 8%, var(--oro) 45%, var(--oro-med) 92%);
      -webkit-background-clip:text; background-clip:text; color:transparent;
    }

    /* Tablas */
    table, .tabla{ width:100%; border-collapse:collapse; font-size:14px; font-family:var(--font-sans) }
    th, .tabla th{
      font-size:11px; letter-spacing:2px; color:var(--oro-med); text-align:left;
      padding:11px 15px; border-bottom:1px solid var(--linea); font-weight:normal;
      text-transform:uppercase; background:none;
    }
    thead tr{ background:none }
    td, .tabla td{ padding:11px 15px; border-bottom:1px solid var(--linea); color:var(--texto); vertical-align:middle }
    tbody tr{ transition:background .25s }
    tbody tr:hover{ background:var(--glow-suave) }
    .oro-t{ color:var(--oro); font-size:17px; font-weight:bold }

    /* Chips, filtros y botones */
    .chip{ font-size:11px; padding:3px 12px; border-radius:20px; border:1px solid; display:inline-block; letter-spacing:1px }
    .chip.ok{ color:var(--verde); border-color:var(--verde) }
    .chip.mal{ color:var(--rojo); border-color:var(--rojo) }
    .chip.oro{ color:var(--oro); border-color:var(--oro-med) }

    .btn, .btn-gold, .btn-primary{
      cursor:pointer; border:none; border-radius:9px; font-family:var(--font-sans);
      font-size:13px; letter-spacing:2px; padding:12px 26px; font-weight:bold;
      color:#141001; background:linear-gradient(170deg, var(--oro-claro), var(--oro) 60%);
      box-shadow:0 12px 32px -12px var(--glow); transition:all .25s;
      display:inline-flex; align-items:center; justify-content:center; gap:8px;
    }
    [data-tema="claro"] .btn, [data-tema="claro"] .btn-gold, [data-tema="claro"] .btn-primary{ color:var(--text-on-gold) }
    .btn:hover, .btn-gold:hover, .btn-primary:hover{ transform:translateY(-2px); color:#141001 }
    [data-tema="claro"] .btn:hover, [data-tema="claro"] .btn-gold:hover, [data-tema="claro"] .btn-primary:hover{ color:var(--text-on-gold) }
    /* Botón secundario: dorado sobre fondo transparente y borde dorado.
       Tiene que leerse ANTES de pasar el mouse — "Cancelar" y "Descartar"
       son la salida, y una salida invisible no es una salida. */
    .btn.linea, .btn-outline,
    button.btn.linea, button.btn-outline{
      background:transparent; color:var(--oro) !important;
      border:1px solid var(--oro-med); box-shadow:none;
    }
    .btn.linea:hover, .btn-outline:hover{
      background:var(--glow-suave); color:var(--oro-claro) !important;
      border-color:var(--oro); transform:translateY(-2px);
    }
    /* Sobre crema, el dorado medio se queda en 4,1:1; el oscuro llega a
       6,6:1 y el botón se lee sin esfuerzo. */
    [data-tema="claro"] .btn.linea, [data-tema="claro"] .btn-outline{ color:var(--oro-claro) !important }
    [data-tema="claro"] .btn.linea:hover, [data-tema="claro"] .btn-outline:hover{ color:var(--oro-claro) !important }
    /* Los de peligro, igual: rojo visible de entrada. */
    .btn-danger, button.btn-danger{ color:var(--rojo) !important }
    .btn-danger:hover{ color:var(--rojo) !important; background:rgba(239,83,80,.12) }
    .btn-danger{ background:transparent; color:var(--rojo); border:1px solid var(--rojo); box-shadow:none }
    .btn-danger:hover{ background:rgba(239,83,80,.10); color:var(--rojo) }
    /* "Devolución" en una pendiente de pago: la acción más delicada, en
       rojo marcada o sin marcar. Sin marcar, contorno rojo; marcada, relleno
       rojo. Sobre el rojo claro del tema oscuro va tinta oscura (6:1) y sobre
       el rojo hondo del claro, blanco (7:1): con blanco al revés no se leería. */
    .btn.pend-rojo, .btn.pend-rojo:hover{
      background:transparent; color:var(--rojo) !important; border:1px solid var(--rojo);
      box-shadow:none;
    }
    .btn.pend-rojo:hover{ background:rgba(239,83,80,.12) }
    .btn.pend-rojo[aria-pressed="true"], .btn.pend-rojo[aria-pressed="true"]:hover{
      background:var(--rojo); color:#141001 !important; border-color:var(--rojo);
      box-shadow:0 12px 32px -12px rgba(239,83,80,.55);
    }
    [data-tema="claro"] .btn.pend-rojo[aria-pressed="true"],
    [data-tema="claro"] .btn.pend-rojo[aria-pressed="true"]:hover{ color:var(--text-on-gold) !important }
    .btn-sm{ padding:7px 16px; font-size:12px; letter-spacing:1px }
    .btn-icon{ width:34px; height:34px; padding:0; border-radius:9px }
    .btn:disabled, .btn[disabled], .btn.is-disabled{ opacity:.45; cursor:not-allowed; transform:none; box-shadow:none }

    /* Formularios */
    label{ color:var(--gris); font-size:12px; letter-spacing:1px }
    input, select, textarea{
      font-family:var(--font-sans); font-size:14px;
      background:var(--n1); border:1px solid var(--linea); color:var(--texto);
      border-radius:9px; padding:10px 13px; color-scheme:dark;
    }
    [data-tema="claro"] input, [data-tema="claro"] select, [data-tema="claro"] textarea{ color-scheme:light; background:var(--n2) }
    input::placeholder, textarea::placeholder{ color:var(--gris-2); font-style:italic }
    input:focus, select:focus, textarea:focus{
      border-color:var(--oro-med); box-shadow:0 0 16px -8px var(--glow); background:var(--n2);
    }
    [data-tema="claro"] input:focus, [data-tema="claro"] select:focus, [data-tema="claro"] textarea:focus{ background:var(--n3) }
    select option{ background:var(--n2); color:var(--texto) }

    /* Avisos */
    .alert{ border-radius:10px; padding:12px 16px; font-size:16px }
    .alert-success{ background:var(--positive-bg); border:1px solid var(--verde); color:var(--verde) }
    .alert-error{ background:var(--negative-bg); border:1px solid var(--rojo); color:var(--rojo) }
    .empty{ color:var(--gris); font-style:italic; text-align:center; padding:40px 20px }
    .empty-icon{ color:var(--oro-med); opacity:.5 }
    .badge{ font-size:11px; padding:3px 12px; border-radius:20px; border:1px solid; display:inline-block; letter-spacing:1px }
    .badge-green{ color:var(--verde); border-color:var(--verde); background:none }
    .text-gold{ color:var(--oro) } .text-green{ color:var(--verde) } .text-red{ color:var(--rojo) }
    .text-muted{ color:var(--gris) }
    .fw-serif{ font-family:var(--font-serif); font-style:italic; color:var(--texto) }

    /* Rejillas y piezas del bento */
    .grid2{ display:grid; grid-template-columns:1fr 1fr; gap:14px }
    .bento{ display:grid; grid-template-columns:minmax(0,1.55fr) minmax(0,1fr); grid-template-rows:auto auto; gap:14px; margin-bottom:20px }
    .bento .card{ margin-bottom:0 }
    .spark{ height:76px; width:100%; display:block; margin-top:auto }
    .barras{ display:flex; align-items:stretch; justify-content:center; gap:6px; height:124px }
    /* Con muchas horas las barras se reparten el ancho; con una sola, el
       tope de 64px evita el pilar gigante que salía antes. */
    .barra{ flex:1 1 0; max-width:64px; display:flex; flex-direction:column; gap:6px; align-items:center; height:100% }
    /* La barra vive DENTRO de esta caja, no en todo el alto de la tarjeta:
       así la hora de abajo siempre tiene su sitio y nunca acaba encima del
       oro. `min-height:0` es lo que permite que la caja se encoja. */
    .barra-caja{ flex:1 1 auto; min-height:0; width:100%; display:flex; flex-direction:column; justify-content:flex-end; align-items:center }
    .barra i{
      width:100%; border-radius:4px 4px 2px 2px; min-height:3px;
      background:linear-gradient(180deg, var(--oro), var(--oro-med));
      box-shadow:0 0 12px -3px var(--glow);
      display:flex; align-items:flex-start; justify-content:center; padding-top:4px;
    }
    /* La cifra SOBRE el oro va en negro y en negrita. Dorado sobre dorado
       no se lee, y justamente ésta es la cifra que se viene a mirar. El
       oro es oro en los dos temas, así que el negro sirve para los dos. */
    .barra i .barra-n{ color:#141001; font-weight:bold; font-size:12.5px; line-height:1 }
    /* Barra demasiado baja para meterle el número dentro: se pone encima, y
       ahí va en el color normal del texto porque el fondo ya no es dorado. */
    .barra-n.fuera{ color:var(--texto); font-weight:bold; font-size:12.5px; line-height:1; margin-bottom:4px }
    /* La hora va fuera de la barra: color de texto normal, no el tenue. */
    .barra small{ font-size:12px; color:var(--gris); flex:0 0 auto; font-variant-numeric:tabular-nums }
    .anillo{ position:relative; width:78px; height:78px; flex-shrink:0 }
    .anillo-txt{ position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center }

    /* ═══════════════════════════════════════════════════════════════════
       "+ REGISTRAR": botón flotante, siempre a mano
    ══════════════════════════════════════════════════════════════════════ */
    #registrar-bar{ display:none }
    /* En el flujo de la hoja y centrado, no flotando sobre el contenido.
       Va ARRIBA del hueco, pegado a la raya dorada del título: el aire
       queda DEBAJO, separándolo de las tarjetas. Antes el hueco se repartía
       casi por igual arriba y abajo y el botón se leía como parte del
       bloque de tarjetas en vez de como parte del encabezado. */
    #registrar-bar.visible{ display:flex; justify-content:center; margin:0 0 34px }
    /* La raya cede su margen de abajo cuando el botón viene detrás: ese
       margen es justo el aire que había que quitar de encima del botón. */
    .raya:has(+ #registrar-bar.visible),
    .gold-line:has(+ #registrar-bar.visible){ margin-bottom:10px }
    #btn-registrar-main{
      position:static; width:auto; min-height:0; max-width:none;
      display:inline-flex; align-items:center; justify-content:center; gap:12px;
      padding:16px 46px; border:none; border-radius:30px;
      background:linear-gradient(170deg, var(--oro-claro), var(--oro) 60%); color:#141001;
      font-family:var(--font-sans); font-size:16px; font-weight:bold; letter-spacing:2px;
      box-shadow:0 14px 34px -14px var(--glow), 0 0 0 1px var(--oro-med);
      transition:all .25s;
    }
    /* El oro NO es el mismo en los dos temas, y por eso la letra tampoco.
       En el oscuro el oro es brillante (#f6c945) y encima va letra oscura.
       En el claro el mismo nombre vale un oro oscuro (#9c7500): ahí la letra
       oscura da 4,49 de contraste —por debajo del mínimo legible— y el
       blanco todavía menos (4,24). Se baja el fondo a --oro-claro (#7a5a00),
       que con blanco da 6,38, y es lo que ya hace .btn-gold en este tema. */
    [data-tema="claro"] #btn-registrar-main{
      background:var(--oro-claro); color:var(--text-on-gold);
    }
    #btn-registrar-main:hover{ transform:translateY(-3px); box-shadow:0 24px 50px -14px var(--glow), 0 0 0 1px var(--oro) }
    #btn-registrar-main .reg-plus{ font-size:20px; line-height:1; margin:0 }

    /* ═══════════════════════════════════════════════════════════════════
       PANTALLA DE ENTRADA Y BLOQUEO
    ══════════════════════════════════════════════════════════════════════ */
    #login-screen{ background:var(--n0); background-image:radial-gradient(1100px 520px at 50% -12%, var(--glow-suave), transparent 60%) }
    .login-card{
      background:linear-gradient(170deg, var(--pagina2) 0%, var(--pagina) 22%);
      border:1px solid var(--oro-dim); border-radius:16px; box-shadow:var(--sombra);
    }
    .login-brand{ font-family:var(--font-serif); font-style:italic; color:var(--texto) }
    .login-brand span{ color:var(--oro) }
    .login-sub{ font-family:var(--font-sans); font-style:normal; font-size:9px; letter-spacing:5px; color:var(--gris-2) }
    /* Página cargada con la sesión bloqueada: ni la libreta ni el login se
       pintan por detrás. No es sólo estética — detrás del candado no debe
       quedar ni un dato del negocio a la vista. */
    body.bloqueada-al-entrar #app,
    body.bloqueada-al-entrar #login-screen,
    body.bloqueada-al-entrar .malla,
    html.bloqueada-al-entrar #app,
    html.bloqueada-al-entrar #login-screen,
    html.bloqueada-al-entrar .malla{ display:none !important }

    .lock-card{ background:linear-gradient(170deg, var(--pagina2) 0%, var(--pagina) 22%); border:1px solid var(--oro-med); border-radius:16px }

    /* ── Modales ──────────────────────────────────────────────────────
       Eran estrechos para lo que se hace dentro (formularios con dos
       columnas, listas de productos). Se ensanchan un 40% —los anchos que
       traía cada uno escritos a mano se recalculan abajo— y el contenido
       crece con ellos: título, campos, botones y aire.
       El tope de 92% del ancho de la ventana los mantiene dentro de
       cualquier pantalla. */
    .modal{
      max-width:min(784px, 92vw);
      padding:0;
    }
    .modal .modal-header, .modal .modal-head{ padding:20px 30px }
    .modal .modal-body{ padding:24px 30px }
    .modal .modal-footer, .modal .modal-foot{ padding:20px 30px }
    .modal .modal-title{ font-size:23px }
    .modal .form-grid{ gap:18px }
    .modal label{ font-size:14px }
    .modal input, .modal select, .modal textarea{ font-size:16px; padding:12px 15px }
    .modal .btn{ font-size:15px; padding:13px 30px }
    .modal .btn-sm{ font-size:14px; padding:9px 20px }
    .modal .btn-row{ gap:12px }

    /* ── Grosor de la letra dentro del modal ──────────────────────────
       El tamaño y el ancho ya estaban bien; lo que se leía flojo era el
       trazo. Un modal se lee de pie, deprisa y a veces con el papel del
       mostrador de por medio, así que dentro va todo más grueso que en
       el resto de la app. Sólo cambia el peso: ni un píxel de tamaño,
       de ancho ni de espaciado se toca aquí.

       Va por PESO y no por tamaño porque la letra de la app es Times New
       Roman, que trae dos trazos (normal y negrita): cualquier valor de
       600 para arriba cae en la negrita real de la fuente, sin que el
       navegador tenga que engordarla él. */
    .modal .modal-body,
    .modal .modal-head, .modal .modal-header,
    .modal .modal-foot, .modal .modal-footer{ font-weight:600 }

    /* Lo que nombra las cosas va un punto más arriba todavía: son las
       palabras que se buscan con el ojo antes de leer nada. */
    .modal label,
    .modal .modal-title,
    .modal .section-title,
    .modal .cap-tipos-section-title,
    .modal .ver-detail-section-title,
    .modal legend,
    .modal dt,
    .modal th{ font-weight:700 }

    /* Lo que el operador escribe y lo que elige en una lista: se lee
       tanto como la etiqueta que lo nombra. */
    .modal input, .modal select, .modal textarea, .modal option{ font-weight:600 }

    /* Las excepciones se respetan solas: los "(opcional)" y las notas al
       pie llevan font-weight:400 escrito en su propia etiqueta, y un
       estilo en línea gana a todo esto. La jerarquía se mantiene. */

    /* Modales: el mismo papel de la hoja. */
    .modal{
      background:linear-gradient(170deg, var(--pagina2) 0%, var(--pagina) 22%);
      border:1px solid var(--oro-dim); border-radius:16px; box-shadow:var(--sombra);
    }
    .modal-header, .modal-head, .modal-footer, .modal-foot{ border-color:var(--linea) }
    .modal-title{ font-family:var(--font-serif); font-style:italic; color:var(--texto); font-size:20px }
    .modal-close{ background:var(--n2); color:var(--gris); border-radius:9px }
    .modal-close:hover{ background:var(--glow-suave); color:var(--oro) }

    /* ═══════════════════════════════════════════════════════════════════
       PANTALLAS CHICAS
    ══════════════════════════════════════════════════════════════════════ */
    @media (max-width:900px){
      #app{ padding:0 12px 40px }
      .top{ flex-wrap:wrap; gap:12px }
      .marca{ font-size:21px }
      #bg-wrap{ order:5; flex:1 1 100%; max-width:none }
      .util{ font-size:10px; gap:10px }
      .bento, .grid2{ grid-template-columns:1fr }
      .cuerpo{ padding:24px 18px 24px 34px }
      .pestana{ letter-spacing:0 }
      .libreta{ margin-top:74px }
      .sesion .qn{ display:none }
      .cantos{ display:none }
      /* En pantalla chica el panel no cabe colgando de la campana: se pone
         fijo, con un dedo de margen a cada lado, y recorre por dentro. Así
         no tapa la barra ni empuja nada de la página. */
      .campana-panel{
        position:fixed; left:10px; right:10px; width:auto; max-width:none;
        /* El `top` real lo pone el JS al abrirla, justo debajo del botón: en
           pantalla chica la barra se parte en dos filas (el buscador baja a
           la suya) y la campana no está siempre a la misma altura. Esto es
           sólo el valor de partida. */
        top:68px; max-height:min(72vh, 520px);
      }
      .campana-btn{ width:36px; height:36px }
      .campana-btn svg{ width:17px; height:17px }
    }
    /* Sólo el símbolo: por debajo de esto, siete nombres no caben sin
       cortarse. El nombre sigue estando en el title de cada pestaña. */
    @media (max-width:720px){
      .pestana{ padding-top:14px }
      .pestana .rotulo{ display:none }
      .pestana .mini{ font-size:19px; margin-bottom:0 }
      .hoja.on .pestana{ padding-top:20px }
    }

    @media (max-width:640px){
      .cuerpo{ padding:22px 14px }
      #btn-registrar-main{ padding:14px 28px; font-size:15px }
    }

    /* En papel sobran los mandos: lo que se imprime es el resultado. */
    @media print{
      .inf-paso, #registrar-bar{ display:none !important }
      .inf-cabecera{ border-top:none; margin-top:0 }
      .gf-card{ break-inside:avoid; page-break-inside:avoid }
    }
    @media print{
      body{ background:#fff }
      .malla, .top, .pestana, .cantos, .subnav, #registrar-bar{ display:none !important }
      .cuerpo{ border:none; box-shadow:none; padding:0; background:none }
      .hoja.on .cuerpo::after{ display:none }
    }
    @media (prefers-reduced-motion:reduce){
      .hoja.on, .section.active{ animation:none !important }
    }
    /* ═══════════════════════════════════════════════════════════════════
       REMATES — lo que quedó del traje anterior dentro de las hojas
       ═══════════════════════════════════════════════════════════════════
       Reglas viejas con el color escrito a mano (blancos sobre fondo
       oscuro, fondos negros fijos). Con el tema claro encendido eran
       texto invisible; aquí vuelven a hablar en variables.
    ══════════════════════════════════════════════════════════════════════ */
    .disp-persona-card-saldo, .disp-hero-value, .ing-cat-label,
    .pm-panel .pm-field-value{ color:var(--texto) }
    .disp-modal-title span, .pm-table-wrap td{ color:var(--texto) }
    .pm-filters input[type="date"]{ background:var(--n1); color:var(--texto); border-color:var(--linea) }
    [data-tema="claro"] .pm-filters input[type="date"]{ background:var(--n2) }
    [data-tema="claro"] .cap-photo-btn:hover,
    [data-tema="claro"] .pa-btn-aprobar,
    [data-tema="claro"] .ver-row-btn.ok{ color:var(--text-on-gold) }

    /* Actividad reciente: renglones de libreta, no tarjetas dentro de una
       tarjeta. La franja de color de cada evento se conserva — es la que
       dice de un vistazo de qué tipo es. */
    #muro-content{ gap:0 }
    #muro-content .muro-card{
      background:transparent; border:none; border-bottom:1px solid var(--linea);
      border-left:3px solid var(--linea); border-radius:0; padding:11px 14px;
      transition:background .25s;
    }
    #muro-content .muro-card:hover{ background:var(--glow-suave) }
    #muro-content .muro-card:last-child{ border-bottom:none }
    .muro-card-icon{ background:var(--glow-suave); color:var(--oro); border-radius:9px }
    .muro-card-titulo{ color:var(--texto); font-weight:bold }
    .muro-card-tiempo{ color:var(--gris-2); font-size:14px; font-style:italic }
    .muro-day-sep{ color:var(--oro-med); font-size:11px; letter-spacing:3px; text-transform:uppercase; padding:12px 14px 6px }
    .muro-empty{ color:var(--gris); font-style:italic; text-align:center; padding:30px }

    /* El resto de piezas heredadas que dan color por su cuenta. */
    .spinner{ border-color:var(--linea); border-top-color:var(--oro) }
    .disp-hero, .ver-row, .precios-card{
      background:linear-gradient(165deg, var(--n3), var(--n1) 70%);
      border:1px solid var(--linea); border-radius:14px;
    }
    .gold-line + .section-sub{ margin-top:-14px }

    /* Cabecera de hoja + índice: cuando la hoja tiene índice, el nombre de
       la página lo dice la pestaña marcada del índice, así que el título
       que cada sección trae dentro sobra — se calla para no repetir
       encabezado. Su subtítulo sí se queda: es el que explica la página. */
    /* El aviso de servidor viejo empuja la página hacia abajo; ahora que
       la página entera se desplaza, no debe además recortarle el alto. */
    body.con-version-banner #app{ height:auto; margin-top:var(--version-banner-h, 42px) }

    .hoja-cabecera{ display:block }
    .cuerpo:has(.subnav.una-sola) .hoja-cabecera{ display:none }
    .subnav.abierta:not(.una-sola) ~ .section .section-title{ display:none }
    .subnav.abierta:not(.una-sola) ~ .section .section-sub{ margin-top:0 }

    /* Los títulos que el chasis escribe como <p> arrastraban el margen de
       párrafo; en la hoja mandan las medidas de la referencia. */
    p.section-title{ margin:0 }
    p.section-sub{ margin:3px 0 0 }

    /* ── Cuenta seleccionada en Disponibles ───────────────────────────
       Al seleccionarla, la tarjeta se pone dorada (.selected cambia el
       fondo a --bg-gold-grad). El texto tiene que cambiar con ella: si no,
       el nombre y el monto se quedan en el color de sobre papel y sobre
       oro no se leen. Va a --text-on-gold, que es el token que ya usan los
       botones dorados y que se da vuelta solo con el tema: tinta oscura
       sobre el oro brillante del tema oscuro, blanco sobre el oro apagado
       del tema claro. Aplica igual a las cuentas en bolívares y a las de
       USDT, que comparten tarjeta. */
    .disp-persona-card.selected .disp-persona-card-name,
    .disp-persona-card.selected .disp-persona-card-saldo,
    .disp-persona-card.selected .disp-persona-card-saldo small,
    .disp-persona-card.selected .disp-persona-card-sub,
    .disp-persona-card.selected .disp-persona-card-badge{ color:var(--text-on-gold) }

    /* Lo secundario (la unidad y el rótulo de abajo) se atenúa, pero sin
       pasarse: con el tema claro el oro es oscuro y hay menos margen. */
    .disp-persona-card.selected .disp-persona-card-saldo small,
    .disp-persona-card.selected .disp-persona-card-sub{ opacity:.72 }
    [data-tema="claro"] .disp-persona-card.selected .disp-persona-card-saldo small,
    [data-tema="claro"] .disp-persona-card.selected .disp-persona-card-sub{ opacity:.9 }

    /* Las insignias ("Cuenta principal", "USDT") llevaban fondo y borde
       propios pensados sobre la tarjeta apagada; sobre el oro se pierden. */
    .disp-persona-card.selected .disp-persona-card-badge{
      background:rgba(0,0,0,.16); border-color:transparent;
    }
    /* El oro del tema claro es oscuro de por sí; para esta tarjeta baja un
       punto más, que es lo que hace legible al blanco de encima. */
    [data-tema="claro"] .disp-persona-card.selected{
      background:linear-gradient(170deg, #6f5200, #8a6600 60%);
    }
    [data-tema="claro"] .disp-persona-card.selected .disp-persona-card-badge{
      background:rgba(255,255,255,.22);
    }

    /* ═══════════════════════════════════════════════════════════════════
       TIPOGRAFÍA DEL PANEL DE VERIFICACIÓN
       ═══════════════════════════════════════════════════════════════════
       Esta pantalla se LEE, no se hojea: son frases —por qué la IA mandó
       una transacción al admin, qué se registró, a qué hora— y estaban
       escritas del tamaño de una etiqueta. Suben dos puntos.

       El tamaño sale de estas tres variables y de ningún otro sitio: para
       moverlo otra vez se tocan aquí, no fila por fila. Van con el ámbito
       de la sección para no arrastrar al resto de la app.

       Quedan fuera a propósito, porque son de mirar y no de leer:
         · el monto de la derecha (.ver-row-monto y su subtítulo),
         · las etiquetas cortas de estado (IA, peso, Vision, observada),
         · los botones de la fila y el índice de arriba.
    ══════════════════════════════════════════════════════════════════════ */
    #section-verificacion{
      --ver-texto: 17px;   /* frases: el titular de la fila y el aviso de la IA */
      --ver-aviso: 16px;   /* el motivo de la IA y la observación guardada */
      --ver-nota:  15px;   /* segunda línea: hora, detalle y pie del aviso */
    }
    #section-verificacion .section-sub{ font-size:18px }
    #section-verificacion .ver-row{ font-size:var(--ver-texto) }
    #section-verificacion .ver-row-titulo{ font-size:var(--ver-texto) }
    #section-verificacion .ver-ia-bar-texto{ font-size:var(--ver-texto) }
    #section-verificacion .ver-row-titulo .ver-row-id,
    #section-verificacion .ver-row-sub,
    #section-verificacion .ver-ia-bar-sub{ font-size:var(--ver-nota) }
    #section-verificacion .ver-ia-motivo,
    #section-verificacion .ver-row-expand-existing,
    #section-verificacion .ver-row-expand textarea{ font-size:var(--ver-aviso) }

    /* ═══════════════════════════════════════════════════════════════════
       REGISTRAR DENTRO DE LA HOJA
       ═══════════════════════════════════════════════════════════════════
       El formulario de registro era un modal y ahora es una sección más.
       Lo que le daba forma (el ancho del modal, su cuerpo con scroll
       propio y el pie con los botones) lo pone aquí la hoja. El formulario
       en sí —campos, validaciones y guardado— no cambia ni una línea.
    ══════════════════════════════════════════════════════════════════════ */
    #section-registrar #cap-body{ max-width:920px }
    #section-registrar .cap-step-hint{ font-size:15px; font-style:italic }

    /* El pie con Descartar / Guardar. Lo enciende el mismo código de
       siempre (style.display = '' cuando el paso 2 está en marcha), así
       que el display de aquí es el que manda cuando está encendido. */
    #section-registrar #cap-footer{
      display:flex; gap:10px; justify-content:flex-end; align-items:center;
      max-width:920px;
      margin-top:24px; padding-top:16px;
      border-top:1px solid var(--linea);
    }

    /* La cabecera del paso 2 se separa un poco del título de la hoja. */
    #section-registrar .cap-back{ margin-top:4px }

    /* El total que manda el catálogo, junto a la lista de la venta. */
    #cap-total-esperado{ display:none }
    #cap-total-esperado.visible{
      display:block; font-size:16px; color:var(--gris);
      border-top:1px solid var(--linea); padding-top:10px; margin-top:2px;
    }
    #cap-total-esperado b{ color:var(--oro); font-size:18px }

    /* Lo que falta para poder guardar. Va pegado al botón, que es donde
       mira el operador cuando no pasa nada al pulsarlo. */
    #cap-falta{ display:none; flex:1; min-width:200px; font-size:15px; line-height:1.45 }
    #cap-falta.visible{ display:block }
    #cap-falta b{ color:var(--oro); font-weight:bold }
    #cap-falta ul{ margin:2px 0 0 18px; padding:0; color:var(--gris) }
    #cap-falta li{ margin:1px 0 }

    /* ═══════════════════════════════════════════════════════════════════
       LETRA CHICA QUE HAY QUE PODER LEER
       ═══════════════════════════════════════════════════════════════════
       Estas notas las lee alguien de pie, con prisa y a veces con la vista
       cansada, en una pantalla que no va a acercar con el navegador porque
       no sabe cómo. Así que ninguna baja de 14 px, y las que ya estaban por
       encima suben dos puntos igual. Donde la estética y la vista se pelean,
       gana la vista.
    ══════════════════════════════════════════════════════════════════════ */
    /* Registrar: la línea que explica cada tipo de transacción. */
    .cap-tipo-card .cap-tipo-sub{ font-size:15.5px; line-height:1.35 }
    .cap-tipos-section-title{ font-size:15px }
    /* Con la nota más grande, alguna tarjeta necesita dos líneas. La
       rejilla estira todas las de la misma fila, así que crecen parejas;
       el mínimo sube para que las de una línea no queden apretadas. */
    .cap-tipo-card{ min-height:88px }
    .cap-tipos-grid{ align-items:stretch }

    /* Cuentas: la nota bajo el nombre de cada cuenta y sus rótulos. */
    .disp-persona-card-sub{ font-size:14px }
    .disp-persona-card-badge{ font-size:14px }
    .disp-persona-card-saldo small{ font-size:14px }
    .disp-group-label{ font-size:15px }
    .disp-hero-label{ font-size:16px }
    .disp-kpi-label{ font-size:15px }
    .disp-persona-card-add .add-label{ font-size:16px }
    .spl-hero-label{ font-size:15px }
    .spl-hero-meta{ font-size:16px }
    .spl-hero-warning{ font-size:15px }
    .spl-badge{ font-size:14px }
    .spl-mov-table thead th{ font-size:15px }

    /* Cierre: lo que sí tiene clase propia. */
    .peso-dia-box{ font-size:17.5px }
    .peso-dia-box .peso-dia-cifras{ font-size:16px }

    /* Que crecer no rompa nada: las notas envuelven en vez de cortarse. */
    .cap-tipo-sub, .disp-persona-card-sub, .spl-hero-meta, .spl-hero-warning{
      white-space:normal; overflow-wrap:anywhere;
    }

    /* ── Dos textos de Administración, dos puntos más grandes ──────────
       El índice de esta hoja es lo que más se pulsa del panel del admin, y
       el botón que dispara la revisión automática es el que se busca con
       prisa. Suben de 13 a 15 px y de 12 a 14. Nada más de esta pantalla
       cambia: el contador de la píldora (el "4"), el ícono de cada
       entrada, el aviso de la IA y las tarjetas de transacción se quedan
       exactamente como estaban.

       El ícono no crece a propósito: la píldora alinea al centro, así que
       un ícono de 13 junto a un texto de 15 sigue centrado, y el conjunto
       queda menos cargado que subiéndolo todo. */
    #subnav-admin .nav-item{ font-size:15px }
    #ver-ia-btn{ font-size:14px }

    /* ── Sobre oro macizo, tinta oscura ────────────────────────────────
       Los rellenos dorados de verdad llevan SIEMPRE --text-on-gold, que se
       da vuelta con el tema. Se listan juntos para que quede a la vista
       cuáles son y para que el próximo que se sume no lo olvide. */
    .btn:not(.linea):not(.btn-outline):not(.btn-danger),
    .btn-gold, .btn-primary, #btn-registrar-main,
    .nav-badge, .pestana .badge, .cap-substep-num,
    .disp-persona-card.selected .disp-persona-card-name,
    .disp-persona-card.selected .disp-persona-card-saldo{ color:var(--text-on-gold) }

    /* Servicio o producto con stock: dos opciones grandes, sin jerga. */
    .psub-tipos{ display:flex; flex-direction:column; gap:8px }
    .psub-tipo{
      display:flex; align-items:flex-start; gap:10px; cursor:pointer;
      padding:10px 12px; border:1px solid var(--linea); border-radius:10px;
      transition:border-color .18s, background .18s;
    }
    .psub-tipo:hover{ border-color:var(--oro-dim); background:var(--glow-suave) }
    .psub-tipo input{ margin-top:3px; accent-color:var(--oro); width:auto }
    .psub-tipo span{ display:flex; flex-direction:column; gap:2px }
    .psub-tipo b{ font-size:15px; color:var(--texto) }
    .psub-tipo small{ font-size:13px; color:var(--gris); font-style:italic }
    .psub-tipo:has(input:checked){ border-color:var(--oro-med); background:var(--glow-suave) }

    /* La fila del producto agotado o por acabarse, en la lista de Precios. */
    .precios-subitem-row.stock-bajo{ border-left:3px solid var(--warning); padding-left:9px }
    .precios-subitem-row.stock-agotado{ border-left:3px solid var(--negative); padding-left:9px }
    /* Al llegar desde el aviso de Inicio, la fila parpadea un momento: la
       lista es larga y "te llevé a Precios" no sirve de nada si hay que
       volver a buscar con el dedo cuál era. */
    .precios-subitem-row.precios-row-senalada{
      animation: precios-senalar 2.4s ease-out;
      border-radius:6px;
    }
    @keyframes precios-senalar{
      0%,55%{ background: rgba(245,197,66,.28) }
      100%  { background: transparent }
    }

    /* ═══════════════════════════════════════════════════════════════════
       AYUDA EN UN "?" — la explicación deja de ocupar pantalla
       ═══════════════════════════════════════════════════════════════════
       Las explicaciones de cómo funciona algo llenaban la vista de letra
       gris que se lee una vez en la vida. Ahora viven detrás de un signo de
       interrogación en la esquina de aquello que explican: se abre con un
       clic (con el mouse y con el dedo, no sólo al pasar por encima) y se
       cierra al tocar fuera o con Esc.

       Lo que NO se esconde: los datos y los estados. Un monto, una fecha,
       un nombre o un aviso de lo que está pasando ahora se quedan a la
       vista. Detrás del "?" sólo va lo que explica cómo funciona algo.
    ══════════════════════════════════════════════════════════════════════ */
    .ayuda{
      flex:0 0 auto;
      width:20px; height:20px; padding:0;
      display:inline-flex; align-items:center; justify-content:center;
      border:none; border-radius:50%;
      background:var(--gris-2); color:var(--n0);
      font-family:var(--font-sans); font-size:13px; font-weight:bold; line-height:1;
      cursor:pointer; opacity:.75;
      transition:opacity .15s, background .15s, transform .15s;
      vertical-align:middle;
    }
    .ayuda:hover, .ayuda[aria-expanded="true"]{ opacity:1; background:var(--oro); color:#141001; transform:scale(1.06) }
    [data-tema="claro"] .ayuda{ color:var(--text-on-gold) }
    [data-tema="claro"] .ayuda:hover, [data-tema="claro"] .ayuda[aria-expanded="true"]{ color:var(--text-on-gold) }
    .ayuda:focus-visible{ outline:2px solid var(--oro); outline-offset:2px }

    /* En una tarjeta o una sección, el "?" va arriba a la derecha. */
    .con-ayuda{ position:relative }
    .con-ayuda > .ayuda{ position:absolute; top:10px; right:10px; z-index:3 }

    /* El globo: uno solo para toda la app, se mueve a donde haga falta. */
    #ayuda-globo{
      position:fixed; z-index:var(--capa-ayuda); display:none;
      max-width:min(340px, 92vw);
      padding:12px 14px;
      background:var(--n2); color:var(--texto);
      border:1px solid var(--oro-dim); border-radius:12px;
      box-shadow:var(--sombra);
      font-family:var(--font-sans); font-size:15px; line-height:1.45;
    }
    #ayuda-globo.abierto{ display:block; animation:ayuda-entra .16s ease-out }
    @keyframes ayuda-entra{ from{ opacity:0; transform:translateY(-4px) } to{ opacity:1; transform:none } }
    #ayuda-globo::before{
      content:''; position:absolute; width:10px; height:10px;
      background:var(--n2); border-left:1px solid var(--oro-dim); border-top:1px solid var(--oro-dim);
      transform:rotate(45deg);
      top:var(--flecha-y, -6px); left:var(--flecha-x, 20px);
    }
    #ayuda-globo.abajo::before{ transform:rotate(225deg) }

    /* En las tarjetas de Configuración el control vive a la derecha, así
       que la esquina se le reserva al "?" para que no se pisen. */
    .cfg-card.con-ayuda{ padding-right:38px }

    /* Rótulo corto + "?" para los formularios: el campo dice qué es y el
       signo guarda la explicación de qué pasa al usarlo. */
    .form-hint-ayuda{
      display:flex; align-items:center; gap:7px;
      font-size:14px; color:var(--gris); margin-bottom:10px; font-style:italic;
    }


    /* ═══════════════════════════════════════════════════════════════════
       ACABADO — NÚMEROS CUADRADOS, FOCO Y APAGADO  (28-oct)
       ═══════════════════════════════════════════════════════════════════

       Tres reglas y ni un color, ni un tamaño de letra, ni un espaciado
       nuevos. Van al FINAL a propósito: aquí ganan por cascada a las casi
       6.000 líneas de arriba, que es lo que permite que valgan en las 19
       pantallas sin ir a tocarlas una por una.
    ══════════════════════════════════════════════════════════════════════ */

    /* ── 1. El dinero cuadra en vertical ──────────────────────────────
       Esta regla ya existía y estaba bien resuelta, pero vivía presa de
       una sola tabla (`.gf-tabla .num`, más arriba en este archivo). Las
       27 celdas de los informes la tenían; las otras 59 de la app pedían
       `class="num"` a un estilo que fuera de esa tabla no existía.

       Las tres partes hacen falta por separado:
         · a la derecha  — las comas caen en la misma vertical;
         · tabular-nums  — el 1 ocupa lo que el 8, así que las cifras no
                           bailan de una fila a la siguiente;
         · nowrap        — "Bs. 148.900,00" no se parte en dos renglones
                           cuando la ventana se estrecha. */
    .num, td.num, th.num{
      text-align: right;
      font-variant-numeric: tabular-nums;
      white-space: nowrap;
    }
    /* Ancho mínimo de la columna de importes. Al filtrar, la cifra más
       larga puede desaparecer: la columna se encogía y las comas saltaban
       de sitio entre una búsqueda y la siguiente. En pantalla estrecha se
       suelta, que ahí cada píxel de ancho vale más que esto. */
    td.num, th.num{ min-width: 8ch }
    @media (max-width: 640px){ td.num, th.num{ min-width: 0 } }

    /* ── 2. El foco de teclado: un anillo, y uno solo ─────────────────
       Había 10 `outline:none` contra 5 reglas de foco, así que quien
       navega con Tab perdía el rastro a media pantalla. Esos diez ya no
       están; el anillo se declara AQUÍ, una vez, y lo hereda todo lo que
       se puede enfocar: botones, campos, selects, enlaces, las pestañas
       de la libreta y las filas con tabindex.

       Va con :focus-visible y no con :focus porque el navegador lo
       enciende al llegar con el teclado y no al hacer clic con el ratón.
       Ésa es la diferencia entre una ayuda y un borde que estorba. */
    :focus-visible{
      outline: 2px solid var(--oro);
      outline-offset: 2px;
    }
    /* Dentro de algo que recorta —la ventanita del chat, la lista de la
       campana, una tabla con desplazamiento— el anillo por fuera se come
       el borde y se ve a medias: ahí va por dentro. */
    .chat-cuerpo :focus-visible,
    .campana-lista :focus-visible,
    .table-wrap :focus-visible{ outline-offset: -2px }

    /* ── 3. Un botón apagado se ve apagado ────────────────────────────
       `.btn:disabled` ya lo hacía bien. Lo que faltaba eran los veinte
       botones con apellido propio que no heredan de .btn —.pa-btn,
       .ct-btn, .cw-btn, .tema-btn, .lock-btn, .cap-back-btn…—: salían
       idénticos a uno vivo y se pulsaban sin que pasara nada. Los de
       aprobar y rechazar del lote de verificación son justo de ésos.

       Se declara sobre el ELEMENTO, no sobre la clase, así que alcanza a
       todos sin tocar ni uno: mismo color, mismo tamaño, mismo padding;
       sólo se apaga. La segunda regla anula el levantarse que cada botón
       trae por su cuenta en :hover. */
    button:disabled, button[disabled], .btn.is-disabled{
      opacity: .45;
      cursor: not-allowed;
      box-shadow: none;
      transform: none;
    }
    button:disabled:hover, button[disabled]:hover, .btn.is-disabled:hover{
      transform: none;
      box-shadow: none;
    }

    /* ═══════════════════════════════════════════════════════════════════
       DATOS DE DESTINO — el interruptor y el formulario (Rich, 5-nov-2026)

       Se ve igual en el escritorio del admin y en el teléfono: el
       interruptor es un BOTÓN grande con su explicación debajo, no un
       conmutador pequeño. En 390 px de ancho un conmutador de 40 px al
       lado de un texto largo es justo lo que no se acierta con el pulgar,
       y aquí un toque de más abre la edición de datos de dinero.
    ══════════════════════════════════════════════════════════════════════ */
    .destino-inter{
      border: 1px solid var(--border);
      border-radius: 10px;
      padding: 12px;
      margin: 4px 0 16px;
      background: var(--bg-elevated);
    }
    /* Encendido se ve verde, con los mismos tonos que el resto del sistema
       (los de .cap-discrep.ok): así cambia solo con el tema claro. */
    .destino-inter.encendido{
      border-color: rgba(90, 181, 116, 0.35);
      background: rgba(90, 181, 116, 0.12);
    }
    .destino-inter.encendido .destino-inter-titulo{ color: var(--positive) }
    .destino-inter-titulo{
      font-weight: 600;
      font-size: 15px;
      margin-bottom: 6px;
    }
    .destino-inter-nota{
      font-size: 13px;
      line-height: 1.4;
      color: var(--text-muted);
      margin-top: 8px;
    }
    .destino-inter .btn{
      width: 100%;
      min-height: 48px;
      font-size: 16px;
    }
    .destino-datos{
      font-size: 14px;
      line-height: 1.5;
      margin: 0 0 12px;
    }
    .destino-datos b{ font-weight: 600 }
    .destino-ref{
      font-size: 13px;
      color: var(--text-muted);
      margin-top: 4px;
    }
    .destino-grid{
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 10px;
    }
    .destino-grid .full{ grid-column: 1 / -1 }
    @media (max-width: 560px){
      .destino-grid{ grid-template-columns: 1fr }
      .destino-inter{ padding: 10px }
    }
