/* ==========================================================================
   Invokard — Zona privada (login · vault · admin)
   --------------------------------------------------------------------------
   SE CARGA SIEMPRE DESPUÉS de css/styles.css, nunca en su lugar:

     <link rel="stylesheet" href="css/styles.css">
     <link rel="stylesheet" href="css/vault.css">

   styles.css aporta el reset, la tipografía, la escala --s1..--s7, los colores
   de mazo, el chaflán y las banderas CSS. Aquí NO se redefine ninguno de esos
   tokens: solo se añaden los que faltaban, con el mismo criterio.

   Reglas de la casa que este archivo respeta (y que los constructores deben
   seguir respetando al escribir el HTML):
   · El padding lateral vive SOLO en los contenedores (.vault-in, .auth-in),
     nunca en los hijos.
   · Nada de texto por debajo de 12px. Las etiquetas mono en mayúsculas con
     letter-spacing van a 12.5–13px, no a 11.
   · El '*{margin:0}' de styles.css mata el margin:auto de <dialog>: aquí se
     repone explícitamente en cada diálogo.
   · Los hijos de grid llevan min-width:0 o desbordan en móvil.
   · Banderas de idioma: se reutilizan .flag / .fl / .fl-es / .fl-en de
     styles.css. Nunca emoji.
   · Cero border-radius. El bisel es --chamfer vía .chamfer o clip-path.

   Convención de color de mazo: el JS pone --d en el elemento
   (style="--d:var(--deck-dev)"), como ya hace la landing. Aquí se lee --d.
   ========================================================================== */

/* ══ 1 · TOKENS ═══════════════════════════════════════════════════════════
   Superficies semánticas propias de la app. Se definen ENTERAS en :root
   (nada existe solo dentro de un media query) y luego se reasignan para el
   tema oscuro en los dos selectores: preferencia del sistema e interruptor. */

:root{
  /* superficies */
  --v-bg:          #FFFFFF;
  --v-surface:     #FFFFFF;
  --v-surface-2:   #F7F7F9;
  --v-surface-3:   #EFEFF3;
  --v-text:        #0C0F16;
  --v-text-2:      #565C6B;
  /* #7A8090 daba 3.95:1 sobre blanco y 3.69:1 sobre --v-surface-2: por debajo
     de AA en el nombre de un mazo bloqueado y en el estado de cada carta, que
     son texto de verdad, no adorno. #676D7D da 5.2:1 y 4.8:1 y mantiene la
     jerarquía con --v-text-2. El valor oscuro ya pasaba y no se toca. */
  --v-text-3:      #676D7D;
  --v-line:        #D6D8DE;
  --v-line-soft:   #E6E7EB;

  /* bloques invertidos (héroe del login, modal de carta, cabeceras oscuras) */
  --v-inv-bg:      #0C0F16;
  --v-inv-text:    #FFFFFF;
  --v-inv-text-2:  rgba(255,255,255,.68);
  --v-inv-text-3:  rgba(255,255,255,.46);
  --v-inv-line:    rgba(255,255,255,.16);
  --v-inv-surface: #141822;

  /* acentos — --accent y --gold vienen de styles.css y no se tocan */
  --v-accent-text: #C4351F;   /* = --accent-ink, 5.4:1 sobre blanco */
  --v-btn-fg:      #FFFFFF;

  /* semáforo de estado (ok / aviso / error) */
  --v-ok:          #0F7A4F;
  --v-ok-bg:       #E7F5EE;
  --v-warn:        #8A5A00;
  --v-warn-bg:     #FCF2DC;
  --v-err:         #B3271A;
  --v-err-bg:      #FBEAE8;
  --v-info:        #12667A;
  --v-info-bg:     #E4F4F8;

  /* trama de puntos Ben-Day sobre fondo claro y sobre fondo oscuro */
  --v-dots:        rgba(12,15,22,.09);
  --v-dots-inv:    rgba(255,255,255,.14);

  /* esqueleto de carga */
  --v-skel:        #E9EAEE;
  --v-skel-hi:     #F5F5F8;

  /* sombras */
  --v-shadow:      0 12px 28px -16px rgba(12,15,22,.42);
  --v-shadow-up:   0 26px 52px -20px rgba(12,15,22,.55);

  /* métrica propia de la app */
  --topbar-h:      60px;
  --v-maxw:        1320px;
  --v-stroke:      1px;        /* trazo fino de retícula */
  --v-stroke-2:    2px;        /* trazo grueso de énfasis */
}

@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --v-bg:          #0C0F16;
    --v-surface:     #12161F;
    --v-surface-2:   #171C27;
    --v-surface-3:   #1E2431;
    --v-text:        #F2F3F6;
    --v-text-2:      #A3A9B8;
    --v-text-3:      #838A9A;
    --v-line:        #2A3040;
    --v-line-soft:   #212734;

    --v-inv-bg:      #060810;
    --v-inv-text:    #FFFFFF;
    --v-inv-text-2:  rgba(255,255,255,.68);
    --v-inv-text-3:  rgba(255,255,255,.46);
    --v-inv-line:    rgba(255,255,255,.16);
    --v-inv-surface: #10141D;

    --v-accent-text: #FF7A5E;   /* 5.6:1 sobre #12161F */
    --v-btn-fg:      #FFFFFF;

    --v-ok:          #4FD69C;
    --v-ok-bg:       rgba(79,214,156,.12);
    --v-warn:        #F0B958;
    --v-warn-bg:     rgba(240,185,88,.12);
    --v-err:         #FF8B7A;
    --v-err-bg:      rgba(255,139,122,.12);
    --v-info:        #5FCEE4;
    --v-info-bg:     rgba(95,206,228,.12);

    --v-dots:        rgba(255,255,255,.10);
    --v-dots-inv:    rgba(255,255,255,.14);

    --v-skel:        #1C222E;
    --v-skel-hi:     #262D3B;

    --v-shadow:      0 12px 28px -16px rgba(0,0,0,.75);
    --v-shadow-up:   0 26px 52px -20px rgba(0,0,0,.85);
  }
}

:root[data-theme="dark"]{
  --v-bg:          #0C0F16;
  --v-surface:     #12161F;
  --v-surface-2:   #171C27;
  --v-surface-3:   #1E2431;
  --v-text:        #F2F3F6;
  --v-text-2:      #A3A9B8;
  --v-text-3:      #838A9A;
  --v-line:        #2A3040;
  --v-line-soft:   #212734;

  --v-inv-bg:      #060810;
  --v-inv-text:    #FFFFFF;
  --v-inv-text-2:  rgba(255,255,255,.68);
  --v-inv-text-3:  rgba(255,255,255,.46);
  --v-inv-line:    rgba(255,255,255,.16);
  --v-inv-surface: #10141D;

  --v-accent-text: #FF7A5E;
  --v-btn-fg:      #FFFFFF;

  --v-ok:          #4FD69C;
  --v-ok-bg:       rgba(79,214,156,.12);
  --v-warn:        #F0B958;
  --v-warn-bg:     rgba(240,185,88,.12);
  --v-err:         #FF8B7A;
  --v-err-bg:      rgba(255,139,122,.12);
  --v-info:        #5FCEE4;
  --v-info-bg:     rgba(95,206,228,.12);

  --v-dots:        rgba(255,255,255,.10);
  --v-dots-inv:    rgba(255,255,255,.14);

  --v-skel:        #1C222E;
  --v-skel-hi:     #262D3B;

  --v-shadow:      0 12px 28px -16px rgba(0,0,0,.75);
  --v-shadow-up:   0 26px 52px -20px rgba(0,0,0,.85);
}


/* ══ 2 · ARMAZÓN DE PÁGINA ════════════════════════════════════════════════ */

/* La landing hace scroll-snap por bloques de pantalla completa. La zona
   privada es una aplicación: se lee de arriba abajo sin imanes. El <html>
   de login.html / dashboard.html / admin.html lleva class="app". */
html.app{ scroll-snap-type:none; scroll-padding-top:var(--topbar-h); }

/* [hidden] es una regla del NAVEGADOR y pierde contra CUALQUIER regla de autor
   que declare display. Sin esta línea `el.hidden = true` no oculta nada dentro
   de .v-pill{display:inline-flex}, .v-msg.is-on{display:flex},
   .adm-inline-actions{display:flex} ni .vd-actions — y los cuatro casos existen
   hoy en el código. Va en el armazón porque afecta a las tres páginas. */
[hidden]{ display:none !important; }

body.app{
  background:var(--v-bg);
  color:var(--v-text);
  font-size:16.5px;
  min-height:100vh; min-height:100svh;
  display:flex; flex-direction:column;
}

/* Único sitio con padding lateral. Nunca lo pongas en un hijo. */
.vault-in,.auth-in{
  width:100%;
  max-width:calc(var(--v-maxw) + var(--s4) * 2);
  margin-inline:auto;
  padding-inline:var(--s4);
}

.vault-main{ flex:1 0 auto; padding-block:var(--s5) var(--s7); }

/* El `background` es OBLIGATORIO aquí: styles.css:310 trae
   `footer{ background:var(--ink) }`, un selector de elemento que alcanza a
   <footer class="vault-foot">. Sin reponerlo, el pie sale negro también en
   tema claro y el texto --v-text-3 encima se queda en 4.0:1, por debajo de AA. */
.vault-foot{
  background:var(--v-bg);
  border-top:var(--v-stroke) solid var(--v-line);
  padding-block:var(--s3);
  /* --v-text-3 sobre --v-bg da 3.95:1 a 14px: por debajo de AA. --v-text-2 da
     6.7:1 en claro y 7.9:1 en oscuro. Un pie ilegible no es un pie discreto. */
  color:var(--v-text-2);
  font-size:14px;
}
.vault-foot .vault-in{ display:flex; gap:var(--s3); flex-wrap:wrap; align-items:center; justify-content:space-between; }
.vault-foot a:hover{ color:var(--v-accent-text); }


/* ══ 3 · BARRA SUPERIOR DE SESIÓN ═════════════════════════════════════════
   Misma retícula de keylines que .nav de la landing: celdas separadas por
   trazo, cero radios, la acción destacada en bloque sólido. */

.vault-top{
  position:sticky; top:0; z-index:40;
  background:var(--v-surface);
  border-bottom:var(--v-stroke) solid var(--v-line);
}
.vt-in{
  max-width:var(--v-maxw); margin-inline:auto;
  display:flex; align-items:stretch; height:var(--topbar-h);
  border-inline:var(--v-stroke) solid var(--v-line);
}

.vt-logo{
  display:flex; align-items:center; gap:9px; min-width:0;
  padding-inline:var(--s3);
  font-family:var(--display); font-size:14px; letter-spacing:.15em;
  color:var(--v-text);
  border-right:var(--v-stroke) solid var(--v-line);
  white-space:nowrap;
}
.vt-logo .star{ background:var(--accent); }

/* Etiqueta de contexto: VAULT / ADMIN. Mono en mayúsculas -> tamaño generoso. */
.vt-badge{
  display:flex; align-items:center; padding-inline:14px;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--v-text-2);
  border-right:var(--v-stroke) solid var(--v-line);
  white-space:nowrap;
}
.vt-badge-admin{ background:var(--accent); color:#FFFFFF; }

/* Empuja el resto a la derecha y absorbe el sobrante. */
.vt-spacer{ flex:1 1 auto; min-width:0; }

.vt-user{
  display:flex; align-items:center; gap:8px; min-width:0;
  padding-inline:var(--s3);
  font-size:15px; color:var(--v-text-2);
  border-left:var(--v-stroke) solid var(--v-line);
}
.vt-user b{ color:var(--v-text); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:20ch; }

/* Selector de idioma: reutiliza .flag/.fl de styles.css. */
.vt-lang{ display:flex; align-items:stretch; border-left:var(--v-stroke) solid var(--v-line); }
.vt-lang .flag{ border-right:var(--v-stroke) solid var(--v-line); }
.vt-lang .flag:last-child{ border-right:0; }
.vt-lang .flag:hover{ background:var(--v-surface-2); }

.vt-btn{
  display:flex; align-items:center; gap:8px;
  padding-inline:18px;
  font-size:14.5px; font-weight:600; color:var(--v-text-2);
  border-left:var(--v-stroke) solid var(--v-line);
  white-space:nowrap;
  transition:background .15s,color .15s;
}
.vt-btn:hover{ background:var(--v-text); color:var(--v-surface); }
.vt-btn-admin{ color:var(--v-accent-text); }
.vt-btn-out:hover{ background:var(--accent); color:#FFFFFF; }
.vt-btn[hidden]{ display:none; }

/* Interruptor de tema — dos glifos cuadrados, sin radios.
   flex:0 0 52px y no width: la barra es un flex y con seis celdas (logo, badge,
   usuario, banderas, tema, admin, salir) a 360px el botón se aplastaba a 18px,
   por debajo del objetivo táctil mínimo. */
.vt-theme{
  display:flex; align-items:center; justify-content:center; flex:0 0 52px;
  border-left:var(--v-stroke) solid var(--v-line);
  color:var(--v-text-2); transition:background .15s,color .15s;
}
.vt-theme:hover{ background:var(--v-surface-2); color:var(--v-text); }
.vt-theme svg{ width:17px; height:17px; }

@media (max-width:860px){
  .vt-badge{ display:none; }
  .vt-user{ padding-inline:var(--s2); }
  .vt-user span[data-i18n]{ display:none; }
  .vt-btn{ padding-inline:14px; }
}
@media (max-width:620px){
  .vault-in,.auth-in{ padding-inline:var(--s3); }
  .vt-in{ border-inline:0; }
  .vt-logo{ padding-inline:var(--s3); font-size:13px; }
  .vt-user b{ max-width:11ch; }
  /* Con seis celdas y un admin logueado, a 360px la barra medía 379 y sacaba
     barra de scroll horizontal a toda la página. El saludo es lo primero que
     sobra en un móvil: el nombre ya está en la propia cuenta. */
  .vt-user{ display:none; }
}
@media (max-width:400px){
  .vt-logo{ padding-inline:12px; }
  .vt-lang .flag{ width:40px; }
  .vt-theme{ flex:0 0 46px; }
  .vt-btn{ padding-inline:11px; font-size:14px; }
}


/* ══ 4 · PRIMITIVAS COMPARTIDAS ═══════════════════════════════════════════ */

/* ── Cabecera de página y de sección ──────────────────────────────────── */
.vault-head{ padding-bottom:var(--s5); max-width:64ch; }
.vault-head h1{
  font-family:var(--display); font-size:clamp(30px,3.6vw,46px);
  line-height:.96; letter-spacing:-.02em; margin-bottom:var(--s2);
  text-wrap:balance;
}
.vault-head p{ color:var(--v-text-2); font-size:17.5px; max-width:56ch; }

.v-sec{ padding-block:var(--s5); border-top:var(--v-stroke) solid var(--v-line); }
.v-sec:first-of-type{ border-top:0; padding-top:0; }

.v-sec-head{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:var(--s3); flex-wrap:wrap; margin-bottom:var(--s4);
}
.v-sec-head > div{ min-width:0; }
.v-tag{
  display:flex; align-items:center; gap:9px;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--v-accent-text); margin-bottom:12px;
}
.v-tag .star{ background:var(--accent); }
.v-sec-title{
  font-family:var(--display); font-size:clamp(22px,2.4vw,30px);
  line-height:.98; letter-spacing:-.01em;
}
.v-sec-desc{ color:var(--v-text-2); font-size:16px; margin-top:10px; max-width:58ch; }

/* Etiqueta mono suelta (contadores, pies de dato). Nunca por debajo de 12px. */
.v-lbl{
  font-family:var(--mono); font-size:12.5px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--v-text-2);
}

/* ── Botones ──────────────────────────────────────────────────────────── */
/* styles.css pone text-align:left en todos los <button>: se repone aquí. */
.v-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  text-align:center; white-space:nowrap;
  font-size:15px; font-weight:700; line-height:1.2;
  padding:14px 26px;
  background:var(--accent); color:#FFFFFF;
  border:var(--v-stroke) solid var(--accent);
  transition:background .15s,border-color .15s,color .15s,transform .15s;
}
.v-btn:hover:not(:disabled){ background:var(--v-text); border-color:var(--v-text); color:var(--v-bg); transform:translateY(-2px); }
.v-btn:disabled{ opacity:.5; cursor:not-allowed; transform:none; }

.v-btn-ghost{ background:transparent; color:var(--v-text); border-color:var(--v-text); }
.v-btn-ghost:hover:not(:disabled){ background:var(--v-text); color:var(--v-bg); }

.v-btn-quiet{ background:transparent; color:var(--v-text-2); border-color:var(--v-line); }
.v-btn-quiet:hover:not(:disabled){ background:var(--v-surface-2); color:var(--v-text); border-color:var(--v-text-2); }

.v-btn-danger{ background:transparent; color:var(--v-err); border-color:var(--v-err); }
.v-btn-danger:hover:not(:disabled){ background:var(--v-err); color:#FFFFFF; }

.v-btn-sm{ padding:9px 15px; font-size:14px; }
.v-btn-lg{ padding:17px 34px; font-size:16px; }
.v-btn-block{ width:100%; }

/* Estado de carga: el texto se atenúa y aparece el aspa giratoria.
   El JS solo añade/quita .is-busy y disabled — nunca reescribe el texto. */
.v-btn.is-busy{ position:relative; color:transparent; pointer-events:none; }
.v-btn.is-busy::after{
  content:""; position:absolute; top:50%; left:50%; width:16px; height:16px;
  margin:-8px 0 0 -8px;
  border:2px solid currentColor; border-top-color:transparent;
  color:#FFFFFF;
  animation:v-spin .7s linear infinite;
}
.v-btn-ghost.is-busy::after,.v-btn-quiet.is-busy::after,.v-btn-danger.is-busy::after{ color:var(--v-text); }
@keyframes v-spin{ to{ transform:rotate(360deg) } }

/* Confirmación momentánea tras copiar / descargar. */
.v-btn.is-done{ background:var(--v-ok); border-color:var(--v-ok); color:#FFFFFF; }

/* ── Campos de formulario ─────────────────────────────────────────────── */
.v-field{ display:flex; flex-direction:column; gap:8px; min-width:0; }
.v-field label,.v-label{
  font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--v-text-2);
}
.v-input,.v-select,.v-textarea{
  width:100%; min-width:0;
  font-family:var(--font); font-size:16px; line-height:1.4; color:var(--v-text);
  background:var(--v-surface);
  border:var(--v-stroke) solid var(--v-line);
  padding:13px 15px;
  transition:border-color .15s,box-shadow .15s,background .15s;
}
.v-input::placeholder,.v-textarea::placeholder{ color:var(--v-text-3); }
.v-input:hover,.v-select:hover,.v-textarea:hover{ border-color:var(--v-text-3); }
.v-input:focus,.v-select:focus,.v-textarea:focus{
  outline:0; border-color:var(--v-accent-text);
  box-shadow:inset 0 0 0 var(--v-stroke) var(--v-accent-text);
}
.v-input:disabled,.v-select:disabled,.v-textarea:disabled{ background:var(--v-surface-2); color:var(--v-text-3); cursor:not-allowed; }
.v-input[aria-invalid="true"]{ border-color:var(--v-err); box-shadow:inset 0 0 0 var(--v-stroke) var(--v-err); }

.v-textarea{ font-family:var(--mono); font-size:13.5px; line-height:1.6; resize:vertical; min-height:220px; }

.v-select{
  appearance:none; padding-right:38px; cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 19px) calc(50% + 1px),calc(100% - 14px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;
  background-repeat:no-repeat;
}

.v-help{ font-size:14px; color:var(--v-text-3); }

/* ── Mensajes en línea (ok / error / aviso / info) ────────────────────── */
.v-msg{
  display:none; align-items:flex-start; gap:10px;
  padding:12px 15px; font-size:15px; line-height:1.5;
  border-left:4px solid var(--v-text-3);
  background:var(--v-surface-2); color:var(--v-text-2);
}
.v-msg.is-on{ display:flex; }
.v-msg.ok  { background:var(--v-ok-bg);   border-left-color:var(--v-ok);   color:var(--v-ok); }
.v-msg.err { background:var(--v-err-bg);  border-left-color:var(--v-err);  color:var(--v-err); }
.v-msg.warn{ background:var(--v-warn-bg); border-left-color:var(--v-warn); color:var(--v-warn); }
.v-msg.info{ background:var(--v-info-bg); border-left-color:var(--v-info); color:var(--v-info); }
.v-msg.busy{ background:var(--v-surface-2); border-left-color:var(--v-text-3); color:var(--v-text-2); }

/* ── Píldoras de estado (tablas de admin, estado de carta) ────────────── */
.v-pill{
  display:inline-flex; align-items:center; gap:6px;
  font-family:var(--mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
  padding:5px 9px; border:var(--v-stroke) solid currentColor;
  white-space:nowrap;
}
.v-pill-ok  { color:var(--v-ok); }
.v-pill-warn{ color:var(--v-warn); }
.v-pill-bad { color:var(--v-err); }
.v-pill-mute{ color:var(--v-text-3); }
.v-pill-deck{ color:var(--d,var(--v-text-2)); }

/* Trama Ben-Day reutilizable sobre bloque oscuro. */
.v-dotted{ position:relative; overflow:hidden; }
.v-dotted::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background-image:radial-gradient(var(--v-dots-inv) 1.4px,transparent 1.4px);
  background-size:9px 9px;
}
.v-dotted > *{ position:relative; }


/* ══ 5 · AUTENTICACIÓN (login / registro / reset) ═════════════════════════ */

.auth-page{ flex:1 0 auto; display:flex; min-height:calc(100svh - var(--topbar-h)); }
.auth-in{
  display:grid; grid-template-columns:1.02fr .98fr;
  align-items:stretch; padding-block:0;
}

/* Panel izquierdo: bloque oscuro con la trama y el abanico de cartas. */
.auth-art{
  background:var(--v-inv-bg); color:var(--v-inv-text);
  padding:var(--s6) var(--s5) var(--s6) 0;
  border-right:var(--v-stroke) solid var(--v-inv-line);
  display:flex; flex-direction:column; justify-content:center;
  min-width:0;
  /* Y el abanico va con bottom:-9%: sin recorte se derrama sobre el blanco de
     debajo en vez de quedar cortado por el canto del bloque. */
  overflow:hidden;
}
.auth-art::before{
  -webkit-mask-image:radial-gradient(ellipse 80% 70% at 30% 45%,#000,transparent 74%);
  mask-image:radial-gradient(ellipse 80% 70% at 30% 45%,#000,transparent 74%);
}
.auth-kicker{
  display:flex; align-items:center; gap:10px;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--gold); margin-bottom:var(--s3);
}
.auth-kicker .star{ background:var(--gold); }
.auth-art h2{
  font-family:var(--display); font-size:clamp(28px,3.2vw,42px); line-height:.96;
  letter-spacing:-.02em; margin-bottom:var(--s3); max-width:14ch; text-wrap:balance;
}
.auth-art p{ color:var(--v-inv-text-2); font-size:17px; max-width:44ch; margin-bottom:var(--s4); }
.auth-art .hl{ color:var(--accent); }

.auth-facts{ display:flex; border-top:var(--v-stroke) solid var(--v-inv-line); max-width:480px; }
.auth-fact{ flex:1; min-width:0; padding:var(--s3) var(--s3) 0 0; }
.auth-fact + .auth-fact{ border-left:var(--v-stroke) solid var(--v-inv-line); padding-left:var(--s3); }
.auth-fact b{ display:block; font-family:var(--display); font-size:28px; line-height:.96; font-variant-numeric:tabular-nums; margin-bottom:6px; }
.auth-fact span{ display:block; font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--v-inv-text-3); }

/* Panel derecho: el formulario. */
.auth-panel{
  padding:var(--s6) 0 var(--s6) var(--s5);
  display:flex; flex-direction:column; justify-content:center;
  align-items:center;          /* centrado en su mitad, no pegado al canto */
  min-width:0;
}
.auth-box{ width:100%; max-width:440px; }

/* ── Pantalla partida de verdad ────────────────────────────────────────────
   Un login a dos mitades quiere llegar a los dos bordes de la ventana. Metido
   en el contenedor centrado se leia como una tira flotante con franjas blancas
   a los lados. Asi que aqui el contenedor NO limita: cada mitad ocupa su lado
   entero y el contenido se acerca al centro, que es donde se mira.
   (Intento anterior descartado: box-shadow con desplazamiento negativo no
   alarga la caja, mueve una copia — la pintaba fuera de la pantalla.) */
@media (min-width:761px){
  .auth-in{ max-width:none; padding-inline:0; }
  .auth-art{
    padding:var(--s6) var(--s5);
    align-items:center;
  }
  .auth-art > *{ width:100%; max-width:520px; }
  /* El formulario, centrado en SU mitad. Arrimado al canto izquierdo dejaba
     un vacio enorme a la derecha y la pagina se leia descompensada. */
  .auth-panel{
    padding:var(--s6) var(--s5);
    align-items:center;
  }
}

.auth-tabs{
  display:grid; grid-template-columns:1fr 1fr;
  border:var(--v-stroke) solid var(--v-line); border-bottom:0;
}
.auth-tab{
  text-align:center; padding:14px 12px;
  font-size:15px; font-weight:600; color:var(--v-text-2);
  border-right:var(--v-stroke) solid var(--v-line);
  transition:background .15s,color .15s;
}
.auth-tab:last-child{ border-right:0; }
.auth-tab:hover{ background:var(--v-surface-2); color:var(--v-text); }
.auth-tab.active{ background:var(--v-text); color:var(--v-bg); }
.auth-tabs[hidden]{ display:none; }

.auth-form{
  display:none; flex-direction:column; gap:var(--s2);
  border:var(--v-stroke) solid var(--v-line);
  padding:var(--s4);
  background:var(--v-surface);
}
.auth-form.active{ display:flex; }
.auth-form h3{ font-family:var(--display); font-size:20px; line-height:1.1; }
.auth-form > p{ color:var(--v-text-2); font-size:15.5px; }

.auth-form .v-btn{ margin-top:var(--s1); }

.auth-forgot{ display:flex; justify-content:flex-end; }
.auth-forgot a{ font-size:14.5px; color:var(--v-accent-text); text-decoration:underline; text-underline-offset:3px; }
.auth-forgot a:hover{ color:var(--v-text); }

.auth-back{
  display:inline-flex; align-items:center; gap:8px; width:fit-content;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--v-text-2);
}
.auth-back:hover{ color:var(--v-accent-text); }

.auth-foot{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  flex-wrap:wrap; margin-top:var(--s3);
  font-size:14.5px; color:var(--v-text-3);
}
.auth-foot a:hover{ color:var(--v-accent-text); }
.auth-foot .lang-switch{ border-left:0; }
.auth-foot .flag{ border-right:0; }

/* .lang-switch y .flag viven en styles.css, calibrado para la landing —que es
   siempre clara— y tiran de --line y --panel. La app tiene tema oscuro: sin
   esto el hover de una bandera enciende un rectángulo casi blanco sobre negro. */
body.app .lang-switch{ border-left-color:var(--v-line); }
body.app .flag{ border-right-color:var(--v-line); }
body.app .flag:hover{ background:var(--v-surface-2); }

/* ── Enlaces dentro del aviso legal del registro ───────────────────────────
   styles.css deja los <a> en `color:inherit; text-decoration:none`, así que los
   enlaces a Términos y Privacidad incrustados en el párrafo eran invisibles. */
.auth-legal-note a{ color:var(--v-accent-text); text-decoration:underline; text-underline-offset:3px; }
.auth-legal-note a:hover{ color:var(--v-text); }

/* ── Carta boca abajo que se gira al cargar el login ───────────────────────
   Puro adorno (aria-hidden, sin eventos). Va detrás del texto: primer hijo,
   position:absolute y z-index:0, recortada por el overflow:hidden de .v-dotted,
   así que asoma por la esquina como una carta apoyada. */
.auth-art .auth-deal{
  position:absolute; z-index:0;
  right:-3%; bottom:-9%;
  width:min(46%,310px); aspect-ratio:3/4;
  perspective:1400px;
  pointer-events:none;
  transform:rotate(-7deg);
}
.auth-deal-inner{
  position:relative; width:100%; height:100%;
  transform-style:preserve-3d;
  animation:auth-turn 1.05s cubic-bezier(.2,.8,.2,1) .28s both;
}
@keyframes auth-turn{ from{ transform:rotateY(180deg) } to{ transform:rotateY(0) } }

.auth-deal-face{ position:absolute; inset:0; backface-visibility:hidden; overflow:hidden; }
.auth-deal-face img{ width:100%; height:100%; object-fit:cover; }

/* Cara vista: filete dorado separado del arte, como el marco de la carta. */
.auth-deal-front{
  box-shadow:0 44px 88px -26px rgba(0,0,0,.85);
  outline:var(--v-stroke) solid var(--gold); outline-offset:5px;
}
/* Reverso: la estrella de la marca dibujada en CSS, nunca un emoji. */
.auth-deal-back{
  transform:rotateY(180deg);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:18px;
  background:var(--v-inv-surface);
  border:var(--v-stroke-2) solid var(--gold);
}
.auth-deal-back .star{ width:54px; height:54px; background:var(--gold); }
.auth-deal-back span{
  font-family:var(--mono); font-size:12.5px; letter-spacing:.28em; text-transform:uppercase;
  color:var(--v-inv-text-3);
}

/* Por debajo de 1100px la columna de arte se queda sin sitio y la carta se
   comería el texto. Nadie echa de menos un adorno. */
@media (max-width:1100px){ .auth-art .auth-deal{ display:none } }

@media (max-width:900px){
  .auth-in{ grid-template-columns:1fr; }
  .auth-art{ padding:calc(var(--topbar-h) + var(--s4)) 0 var(--s4); border-right:0; border-bottom:var(--v-stroke) solid var(--v-inv-line); }
  .auth-art h2{ max-width:20ch; }
  .auth-panel{ padding:var(--s5) 0; }
  .auth-box{ max-width:none; }
}


/* ══ 6 · SUSCRIPCIÓN ══════════════════════════════════════════════════════
   Tres estados excluyentes en el mismo hueco: libre (oferta), activa,
   con incidencia (past_due) o cancelada pero vigente. */

.sub-card{
  display:grid; grid-template-columns:minmax(0,1fr) auto;
  gap:var(--s4); align-items:center;
  border:var(--v-stroke) solid var(--v-line);
  padding:var(--s4);
  background:var(--v-surface);
}
.sub-card > *{ min-width:0; }
.sub-card h3{ font-family:var(--display); font-size:21px; line-height:1.1; margin-bottom:10px; }
.sub-card p{ color:var(--v-text-2); font-size:16px; max-width:56ch; }

.sub-badge{
  display:inline-flex; align-items:center; gap:8px; width:fit-content;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase;
  padding:6px 11px; margin-bottom:var(--s2);
  background:var(--accent); color:#FFFFFF;
}

.sub-perks{ list-style:none; display:grid; gap:10px; margin-top:var(--s3); }
.sub-perks li{ position:relative; padding-left:22px; font-size:16px; color:var(--v-text-2); }
.sub-perks li::before{ content:""; position:absolute; left:0; top:.58em; width:8px; height:8px; background:var(--accent); }

.sub-cta{ display:flex; flex-direction:column; align-items:flex-end; gap:var(--s2); text-align:right; }
.sub-price{ display:flex; align-items:baseline; gap:6px; }
.sub-price b{ font-family:var(--display); font-size:clamp(34px,3.6vw,46px); line-height:.9; letter-spacing:-.02em; }
.sub-price span{ font-family:var(--mono); font-size:13px; color:var(--v-text-2); }

.sub-note{ font-family:var(--mono); font-size:12.5px; letter-spacing:.04em; color:var(--v-text-3); margin-top:12px; }
.sub-note-warn{ color:var(--v-warn); }

/* Oferta: bloque oscuro con trama, como el plan destacado de la landing. */
.sub-card.is-free{ background:var(--v-inv-bg); color:var(--v-inv-text); border-color:var(--v-inv-line); }
.sub-card.is-free p{ color:var(--v-inv-text-2); }
.sub-card.is-free .sub-perks li{ color:var(--v-inv-text-2); }
.sub-card.is-free .sub-perks li::before{ background:var(--gold); }
.sub-card.is-free .sub-price span{ color:var(--v-inv-text-3); }
.sub-card.is-free .sub-note{ color:var(--v-inv-text-3); }

.sub-card.is-active{ border-left:4px solid var(--v-ok); }
.sub-card.is-active .sub-badge{ background:var(--v-ok); }
.sub-card.is-cancelling{ border-left:4px solid var(--v-warn); }
.sub-card.is-cancelling .sub-badge{ background:var(--v-warn); color:#0C0F16; }
.sub-card.is-past-due{ border-left:4px solid var(--v-err); }
.sub-card.is-past-due .sub-badge{ background:var(--v-err); }

@media (max-width:820px){
  .sub-card{ grid-template-columns:1fr; }
  .sub-cta{ align-items:flex-start; text-align:left; }
}


/* ══ 7 · PROGRESO POR MAZO ════════════════════════════════════════════════ */

.deck-stats{ display:grid; gap:var(--s3); }

.ds-summary{
  display:flex; align-items:baseline; gap:var(--s3); flex-wrap:wrap;
  padding-bottom:var(--s3); border-bottom:var(--v-stroke) solid var(--v-line);
}
.ds-figure{ display:flex; align-items:baseline; gap:9px; }
.ds-figure b{ font-family:var(--display); font-size:32px; line-height:.9; font-variant-numeric:tabular-nums; }
.ds-figure span{ font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--v-text-2); }
.ds-sep{ color:var(--v-line); }

.ds-grid{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
  border-top:var(--v-stroke) solid var(--v-line);
  border-left:var(--v-stroke) solid var(--v-line);
}
.deck-chip{
  min-width:0; padding:var(--s3) var(--s2);
  border-right:var(--v-stroke) solid var(--v-line);
  border-bottom:var(--v-stroke) solid var(--v-line);
  background:var(--v-surface);
  transition:background .15s;
}
.deck-chip:hover{ background:var(--v-surface-2); }

.dc-top{ display:flex; align-items:center; gap:8px; margin-bottom:10px; }
.dc-sw{ width:10px; height:10px; flex:0 0 auto; background:var(--d,var(--v-text-3)); }
.dc-name{ font-size:15.5px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dc-count{
  margin-left:auto; flex:0 0 auto;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.04em;
  color:var(--v-text-2); font-variant-numeric:tabular-nums;
}

/* Barra de progreso: rectángulo puro, sin radios. */
.dc-bar{ height:6px; background:var(--v-surface-3); overflow:hidden; }
.dc-bar-fill{ display:block; height:100%; width:0; background:var(--d,var(--v-text-3)); transition:width .5s cubic-bezier(.2,.7,.2,1); }

.deck-chip.is-locked{ background:var(--v-surface-2); }
.deck-chip.is-locked .dc-name{ color:var(--v-text-3); }
.deck-chip.is-locked .dc-sw{ background:var(--v-line); }
.deck-chip.is-locked .dc-bar-fill{ background:var(--v-line); }

/* Mazo completo: el borde grueso dorado es el único premio visual. */
.deck-chip.is-mastered{ box-shadow:inset 0 0 0 var(--v-stroke-2) var(--gold); }
.dc-flag{
  display:none; margin-top:10px;
  font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--v-warn);
}
.deck-chip.is-mastered .dc-flag{ display:block; }


/* ══ 8 · CANJE DE CÓDIGO ══════════════════════════════════════════════════ */

.redeem{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);
  gap:var(--s4); align-items:center;
  border:var(--v-stroke) solid var(--v-line);
  background:var(--v-surface-2);
  padding:var(--s4);
}
.redeem > *{ min-width:0; }
.redeem h3{ font-family:var(--display); font-size:21px; line-height:1.1; margin-bottom:10px; }
.redeem p{ color:var(--v-text-2); font-size:16px; max-width:50ch; }

.redeem-form{ display:grid; grid-template-columns:minmax(0,1fr) auto; gap:0; }
.redeem-form > *{ min-width:0; }

/* El código es un dato técnico: mono, mayúsculas y espaciado generoso. */
#redeem-code{
  font-family:var(--mono); font-size:17px; letter-spacing:.16em; text-transform:uppercase;
  border-right:0; padding-block:15px;
}
#redeem-code::placeholder{ letter-spacing:.1em; text-transform:none; }

.redeem-form .v-btn{ padding-inline:24px; }
.redeem-msg{ margin-top:var(--s2); }

@media (max-width:820px){
  .redeem{ grid-template-columns:1fr; }
}
@media (max-width:480px){
  .redeem-form{ grid-template-columns:1fr; }
  #redeem-code{ border-right:var(--v-stroke) solid var(--v-line); }
}


/* ══ 9 · REJILLA DEL VAULT ════════════════════════════════════════════════ */

.vault-tools{ display:flex; align-items:center; gap:var(--s2); flex-wrap:wrap; }
.vault-tools .v-select{ min-width:210px; padding-block:11px; }
.vault-tools .v-input{ min-width:220px; padding-block:11px; }

.vault-wall{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(196px,1fr));
  gap:var(--s4) var(--s3);
}

.v-card{
  display:block; width:100%; min-width:0; text-align:left;
  perspective:900px;
  content-visibility:auto; contain-intrinsic-size:auto 300px;
}
.vc-thumb{
  display:block; position:relative; overflow:hidden;
  box-shadow:var(--v-shadow);
  transform:rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)); transform-style:preserve-3d;
  transition:transform .42s cubic-bezier(.2,1.25,.4,1),box-shadow .25s,filter .25s;
}
.vc-thumb img{ display:block; width:100%; aspect-ratio:3/4; object-fit:cover; }

/* Brillo foil siguiendo el puntero, invisible hasta el hover. */
.vc-thumb::after{
  content:""; position:absolute; inset:0; opacity:0; pointer-events:none;
  transition:opacity .28s;
  background:radial-gradient(circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.42),rgba(255,255,255,.07) 34%,transparent 60%);
}
.v-card:hover .vc-thumb,.v-card:focus-visible .vc-thumb{ box-shadow:var(--v-shadow-up); }
.v-card:hover .vc-thumb::after{ opacity:1; }
.v-card:active .vc-thumb{ transform:scale(.985); }

.vc-meta{ display:flex; align-items:center; gap:7px; margin-top:10px; min-width:0; }
.vc-sw{ width:8px; height:8px; flex:0 0 auto; background:var(--d,var(--v-text-3)); }
.vc-name{ font-size:16px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.v-card:hover .vc-name{ color:var(--v-accent-text); }

.vc-state{
  display:block; margin-top:4px; padding-left:15px;
  font-family:var(--mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--v-text-3);
}
.vc-state.is-sub{ color:var(--v-accent-text); }

/* ── Carta bloqueada ──────────────────────────────────────────────────── */
/* Desaturada y con candado: se ve que existe, se ve que no es tuya. */
.v-card.is-locked .vc-thumb{ filter:grayscale(1) contrast(.82) brightness(.94); }
.v-card.is-locked:hover .vc-thumb{ filter:grayscale(.55) contrast(.9) brightness(.97); }
.v-card.is-locked .vc-thumb::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:rgba(12,15,22,.42);
}
.vc-lock{
  position:absolute; z-index:2; top:0; right:0;
  width:38px; height:38px; display:none;
  align-items:center; justify-content:center;
  background:var(--v-inv-bg); color:var(--v-inv-text-2);
  border-left:var(--v-stroke) solid var(--v-inv-line);
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
}
.vc-lock svg{ width:15px; height:15px; }
.v-card.is-locked .vc-lock{ display:flex; }
.v-card.is-locked .vc-name{ color:var(--v-text-3); }
.v-card.is-locked:hover .vc-name{ color:var(--v-text-2); }

@media (max-width:560px){
  .vault-wall{ grid-template-columns:repeat(2,1fr); gap:var(--s3) 10px; }
  .vault-tools .v-select,.vault-tools .v-input{ min-width:0; width:100%; }
}


/* ══ 10 · MODAL DE CARTA ══════════════════════════════════════════════════
   Panel oscuro a pantalla casi completa, hermano de #card-dialog de la
   landing pero con cuerpo de prompt y acciones. */

/* margin:auto repone el centrado que mata el '*{margin:0}' de styles.css. */
#vault-dialog{
  border:0; padding:0; margin:auto; background:transparent;
  width:100%; max-width:min(1120px,94vw); max-height:92vh;
  color:var(--v-inv-text);
}
#vault-dialog::backdrop{ background:rgba(6,8,13,.86); backdrop-filter:blur(3px); }

.vd-in{
  display:flex; flex-direction:column;
  max-height:92vh; min-height:0;
  background:var(--v-inv-bg);
  border:var(--v-stroke) solid var(--v-inv-line);
  position:relative;
}

.vd-close{
  position:absolute; top:0; right:0; z-index:3;
  width:46px; height:46px; display:flex; align-items:center; justify-content:center;
  color:var(--v-inv-text-2);
  border-left:var(--v-stroke) solid var(--v-inv-line);
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  transition:background .15s,color .15s;
}
.vd-close:hover{ background:var(--accent); color:#FFFFFF; }

/* ── Cabecera ─────────────────────────────────────────────────────────── */
.vd-head{
  display:flex; align-items:center; gap:var(--s3);
  padding:var(--s3) 56px var(--s3) var(--s4);
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  flex:0 0 auto; min-width:0;
}
.vd-art{ flex:0 0 auto; width:76px; }
.vd-art img{
  display:block; width:100%; aspect-ratio:3/4; object-fit:cover;
  outline:var(--v-stroke) solid var(--d,var(--v-inv-line)); outline-offset:3px;
}
.vd-headings{ min-width:0; }
.vd-deck{
  display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--d,var(--gold)); margin-bottom:9px;
}
.vd-sw{ width:9px; height:9px; flex:0 0 auto; background:var(--d,var(--gold)); }
.vd-type{ color:var(--v-inv-text-3); border-left:var(--v-stroke) solid var(--v-inv-line); padding-left:9px; }
.vd-title{ font-family:var(--display); font-size:clamp(21px,2.4vw,30px); line-height:1.06; }

/* ── Pestañas de idioma del prompt ────────────────────────────────────── */
.vd-langs{
  display:flex; align-items:stretch; flex-wrap:wrap;
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  flex:0 0 auto;
}
.vd-langs-lbl{
  display:flex; align-items:center; padding-inline:var(--s4);
  font-family:var(--mono); font-size:12.5px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--v-inv-text-3);
  border-right:var(--v-stroke) solid var(--v-inv-line);
}
.vd-lang{
  padding:12px 18px;
  font-family:var(--mono); font-size:13px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--v-inv-text-2);
  border-right:var(--v-stroke) solid var(--v-inv-line);
  transition:background .15s,color .15s;
}
.vd-lang:hover{ background:rgba(255,255,255,.08); color:var(--v-inv-text); }
.vd-lang.active{ background:var(--v-inv-text); color:var(--v-inv-bg); }
/* Idioma que esa carta no tiene: visible pero inerte, para que se note que
   el hueco existe y no parezca que la interfaz se ha comido una pestaña. */
.vd-lang.is-off{ color:var(--v-inv-text-3); opacity:.42; cursor:not-allowed; pointer-events:none; }

@media (max-width:620px){
  .vd-langs-lbl{ display:none; }
}

/* ── Acciones ─────────────────────────────────────────────────────────── */
.vd-actions{
  display:flex; flex-wrap:wrap; align-items:stretch;
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  flex:0 0 auto;
}
.vd-act{
  display:flex; align-items:center; gap:8px; text-align:left;
  padding:14px 20px;
  font-size:14.5px; font-weight:600; color:var(--v-inv-text-2);
  border-right:var(--v-stroke) solid var(--v-inv-line);
  transition:background .15s,color .15s;
  white-space:nowrap;
}
.vd-act:hover:not(:disabled){ background:rgba(255,255,255,.09); color:var(--v-inv-text); }
.vd-act:disabled{ opacity:.45; cursor:not-allowed; }
.vd-act svg{ width:15px; height:15px; flex:0 0 auto; }
.vd-act-primary{ background:var(--accent); color:#FFFFFF; }
.vd-act-primary:hover:not(:disabled){ background:#FFFFFF; color:var(--v-inv-bg); }
.vd-act-native{ color:var(--gold); }
.vd-act.is-done{ background:var(--v-ok); color:#FFFFFF; }

.vd-hint{
  padding:12px var(--s4); flex:0 0 auto;
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  font-size:14px; line-height:1.55; color:var(--v-inv-text-3);
}
.vd-hint code{
  font-family:var(--mono); font-size:12.5px;
  background:rgba(255,255,255,.09); color:var(--v-inv-text-2);
  padding:2px 6px;
}

/* ── Cuerpo desplazable ───────────────────────────────────────────────── */
.vd-body{ flex:1 1 auto; min-height:0; overflow-y:auto; padding:var(--s4); }

/* El prompt: monoespaciada, respetando saltos, seleccionable de una pieza. */
.vd-prompt{
  font-family:var(--mono); font-size:13.5px; line-height:1.7;
  color:var(--v-inv-text-2);
  white-space:pre-wrap; word-break:break-word;
  background:var(--v-inv-surface);
  border:var(--v-stroke) solid var(--v-inv-line);
  border-left:3px solid var(--d,var(--v-inv-line));
  padding:var(--s3);
  max-width:96ch;
}

/* ── Panel de instalación (una vía abierta, el resto plegado) ─────────── */
.vd-install{ margin-top:var(--s4); border-top:var(--v-stroke) solid var(--v-inv-line); padding-top:var(--s4); }
.vd-install h3{ font-family:var(--display); font-size:19px; line-height:1.12; margin-bottom:10px; }
.vd-install > p{ color:var(--v-inv-text-2); font-size:15.5px; margin-bottom:var(--s3); max-width:62ch; }

/* Una vía abierta y el resto plegado: se acabaron las sub-pestañas. Cada vía
   es una caja con el mismo filete que tenía el panel de pestañas, así que el
   peso visual del bloque no cambia; lo que cambia es que solo hay UNA a la
   vista al abrir. */
.vd-way{ border:var(--v-stroke) solid var(--v-inv-line); padding:var(--s3); }
.vd-way + .vd-way{ border-top:0; }
.vd-way > p{ font-size:15.5px; line-height:1.6; color:var(--v-inv-text-2); max-width:62ch; }
.vd-way > p + *{ margin-top:var(--s2); }
.vd-way > * + p{ margin-top:var(--s2); }
/* El botón de copiar que vive dentro de una vía. Se separa de los pasos que
   vienen debajo para que se lea como la acción que abre el procedimiento, no
   como un paso más de la lista. */
.vd-way-act{ display:flex; margin-bottom:var(--s2); }
.vd-way-act .vd-act{ flex:0 0 auto; }

.vd-way-h{
  font-size:13px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  color:var(--v-inv-text-2); margin-bottom:var(--s2);
}

/* El desplegable. El triángulo propio del navegador se retira y se dibuja uno
   que gira, porque el nativo no hereda el color del tema y en oscuro se pierde. */
.vd-more{ margin-top:var(--s3); }
.vd-more > summary{
  display:flex; align-items:center; gap:10px;
  padding:11px 14px; cursor:pointer; list-style:none;
  border:var(--v-stroke) solid var(--v-inv-line);
  font-size:14.5px; font-weight:600; color:var(--v-inv-text-2);
  transition:background .15s,color .15s;
}
.vd-more > summary::-webkit-details-marker{ display:none; }
.vd-more > summary::before{
  content:""; flex:none; width:7px; height:7px;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(-45deg); transition:transform .18s;
}
.vd-more[open] > summary::before{ transform:rotate(45deg); }
.vd-more > summary:hover{ background:rgba(255,255,255,.08); color:var(--v-inv-text); }
.vd-more > summary:focus-visible{ outline:2px solid var(--v-inv-text); outline-offset:-2px; }
.vd-more[open] > summary{ border-bottom:0; }
.vd-more-plugin{ margin-top:var(--s4); }
@media (prefers-reduced-motion: reduce){
  .vd-more > summary::before{ transition:none; }
}

.vd-step{ display:flex; gap:14px; align-items:flex-start; padding-block:11px; }
.vd-step + .vd-step{ border-top:var(--v-stroke) solid var(--v-inv-line); }
.vd-step-n{
  flex:0 0 auto; width:26px; height:26px;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--mono); font-size:13px; font-weight:500;
  background:var(--accent); color:#FFFFFF;
}
.vd-step p{ font-size:15.5px; color:var(--v-inv-text-2); min-width:0; }

.vd-code{ position:relative; margin-block:var(--s2); }
.vd-code pre{
  overflow-x:auto;
  font-family:var(--mono); font-size:13px; line-height:1.65;
  color:var(--v-inv-text-2);
  background:var(--v-inv-surface);
  border:var(--v-stroke) solid var(--v-inv-line);
  padding:14px 52px 14px 14px;
}
.vd-copy{
  position:absolute; top:0; right:0;
  width:38px; height:38px; display:flex; align-items:center; justify-content:center;
  color:var(--v-inv-text-2);
  border-left:var(--v-stroke) solid var(--v-inv-line);
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  transition:background .15s,color .15s;
}
.vd-copy:hover{ background:var(--accent); color:#FFFFFF; }
.vd-copy.is-done{ background:var(--v-ok); color:#FFFFFF; }

.vd-tip{
  margin-top:var(--s2); padding:12px 14px;
  border-left:3px solid var(--gold);
  background:rgba(245,185,66,.10);
  font-size:15px; line-height:1.55; color:var(--v-inv-text-2);
}

@media (max-width:820px){
  .vd-head{ padding-inline:var(--s3) 56px; }
  .vd-art{ width:60px; }
  .vd-body{ padding:var(--s3); }
  .vd-act{ padding:12px 15px; font-size:14px; }
  .vd-hint{ padding-inline:var(--s3); }
}


/* ══ 11 · REVELADO DE CARTA (tras un canje correcto) ══════════════════════ */

.reveal-ov{
  position:fixed; inset:0; z-index:60;
  display:flex; align-items:center; justify-content:center;
  padding:var(--s4);
  background:rgba(6,8,13,.92);
  animation:v-fade .22s ease both;
}
.reveal-ov.is-closing{ animation:v-fade .22s ease reverse both; }
@keyframes v-fade{ from{ opacity:0 } to{ opacity:1 } }

.rv-stage{ display:flex; flex-direction:column; align-items:center; gap:var(--s3); text-align:center; max-width:340px; }
.rv-kicker{
  font-family:var(--mono); font-size:13px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--gold);
}
.rv-flip{ width:min(64vw,260px); aspect-ratio:3/4; perspective:1200px; }
.rv-inner{
  position:relative; width:100%; height:100%; transform-style:preserve-3d;
  animation:v-flip .9s cubic-bezier(.2,.8,.2,1) .18s both;
}
@keyframes v-flip{ from{ transform:rotateY(180deg) } to{ transform:rotateY(0) } }
.rv-face{ position:absolute; inset:0; backface-visibility:hidden; overflow:hidden; }
.rv-face img{ width:100%; height:100%; object-fit:cover; }
.rv-back{
  transform:rotateY(180deg);
  display:flex; align-items:center; justify-content:center;
  background:var(--v-inv-surface);
  border:var(--v-stroke-2) solid var(--gold);
  color:var(--gold); font-family:var(--display); font-size:44px;
}
/* El centrado no es decorativo: si cardImage() viniera vacío o la imagen fallara,
   billing.js pinta el sigilo del mazo aquí dentro y sin esto se queda arriba a la
   izquierda, descuadrado respecto al reverso. */
.rv-front{
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 40px 84px -24px rgba(0,0,0,.85);
  outline:var(--v-stroke) solid var(--d,var(--gold)); outline-offset:5px;
}
.rv-title{ font-family:var(--display); font-size:24px; line-height:1.08; color:#FFFFFF; }
.rv-deck{
  font-family:var(--mono); font-size:12.5px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--d,var(--gold));
}


/* ══ 12 · ADMIN ═══════════════════════════════════════════════════════════ */

.adm-nav{
  display:flex; flex-wrap:wrap;
  border-bottom:var(--v-stroke) solid var(--v-line);
  background:var(--v-surface);
  position:sticky; top:var(--topbar-h); z-index:30;
}
.adm-nav-in{
  max-width:var(--v-maxw); margin-inline:auto; width:100%;
  display:flex; flex-wrap:wrap;
  border-inline:var(--v-stroke) solid var(--v-line);
}
.adm-nav-btn{
  padding:14px 20px;
  font-size:14.5px; font-weight:600; color:var(--v-text-2);
  border-right:var(--v-stroke) solid var(--v-line);
  transition:background .15s,color .15s;
  white-space:nowrap;
}
.adm-nav-btn:hover{ background:var(--v-surface-2); color:var(--v-text); }
.adm-nav-btn.active{ background:var(--v-text); color:var(--v-bg); }

.adm-panel{ display:none; padding-block:var(--s5); }
.adm-panel.active{ display:block; }

/* ── Tarjetas de cifra ────────────────────────────────────────────────── */
.adm-stats{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  border-top:var(--v-stroke) solid var(--v-line);
  border-left:var(--v-stroke) solid var(--v-line);
}
.adm-stat{
  min-width:0; padding:var(--s3);
  border-right:var(--v-stroke) solid var(--v-line);
  border-bottom:var(--v-stroke) solid var(--v-line);
  background:var(--v-surface);
}
.adm-stat b{ display:block; font-family:var(--display); font-size:34px; line-height:.9; font-variant-numeric:tabular-nums; margin-bottom:9px; }
.adm-stat span{ display:block; font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--v-text-2); }

/* ── Barra de herramientas de un panel ────────────────────────────────── */
.adm-tools{
  display:flex; align-items:flex-end; gap:var(--s2); flex-wrap:wrap;
  padding:var(--s3);
  border:var(--v-stroke) solid var(--v-line);
  background:var(--v-surface-2);
  margin-bottom:var(--s3);
}
.adm-tools .v-field{ flex:0 1 auto; }
.adm-tools .v-input,.adm-tools .v-select{ padding-block:11px; }
.adm-tools .v-btn{ padding-block:12px; }

/* ── Tabla ────────────────────────────────────────────────────────────── */
.adm-table-head{
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--s2); flex-wrap:wrap;
  padding:var(--s2) var(--s3);
  border:var(--v-stroke) solid var(--v-line); border-bottom:0;
  background:var(--v-surface-2);
}
.adm-table-head h3{ font-family:var(--display); font-size:18px; line-height:1.1; }

/* Una tabla ancha SIEMPRE hace scroll dentro de su caja. El <body> nunca. */
.adm-table-wrap{ width:100%; overflow-x:auto; border:var(--v-stroke) solid var(--v-line); }

.adm-table{ width:100%; border-collapse:collapse; font-size:15px; min-width:720px; }
.adm-table th,.adm-table td{
  text-align:left; padding:12px 14px; vertical-align:middle;
  border-bottom:var(--v-stroke) solid var(--v-line-soft);
}
.adm-table th{
  font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--v-text-2); font-weight:500;
  background:var(--v-surface-2);
  border-bottom:var(--v-stroke) solid var(--v-line);
  position:sticky; top:0; z-index:1;
  white-space:nowrap;
}
.adm-table tbody tr:hover{ background:var(--v-surface-2); }
.adm-table tbody tr:last-child td{ border-bottom:0; }
.adm-table td.num{ font-family:var(--mono); font-variant-numeric:tabular-nums; }
.adm-table td.code{ font-family:var(--mono); font-size:14px; letter-spacing:.08em; }
.adm-table td.actions{ white-space:nowrap; }
.adm-table td.actions .v-btn{ padding:7px 12px; font-size:13.5px; }
.adm-table td.actions .v-btn + .v-btn{ margin-left:6px; }
.adm-table .empty-row td{ text-align:center; padding:var(--s5); color:var(--v-text-3); }

/* ── Editor de skills ─────────────────────────────────────────────────── */
.adm-skills{ display:grid; gap:var(--s3); }
.adm-skill{ border:var(--v-stroke) solid var(--v-line); background:var(--v-surface); }
.adm-skill-head{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:var(--s2) var(--s3);
  border-bottom:var(--v-stroke) solid var(--v-line);
  background:var(--v-surface-2);
}
.adm-skill-head .dc-sw{ width:10px; height:10px; }
.adm-skill-head strong{ font-size:16px; }
.adm-skill-head .adm-slug{ font-family:var(--mono); font-size:12.5px; color:var(--v-text-3); }
.adm-skill-head .v-btn{ margin-left:auto; }

.adm-skill-langs{ display:flex; flex-wrap:wrap; border-bottom:var(--v-stroke) solid var(--v-line); }
.adm-skill-lang{
  padding:9px 15px;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--v-text-2);
  border-right:var(--v-stroke) solid var(--v-line);
  transition:background .15s,color .15s;
}
.adm-skill-lang:hover{ background:var(--v-surface-2); color:var(--v-text); }
.adm-skill-lang.active{ background:var(--v-text); color:var(--v-bg); }

.adm-skill-panel{ display:none; padding:var(--s3); }
.adm-skill-panel.active{ display:block; }
.adm-skill-foot{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s2);
  flex-wrap:wrap; margin-top:10px;
}
.adm-chars{ font-family:var(--mono); font-size:12.5px; color:var(--v-text-3); font-variant-numeric:tabular-nums; }

/* ── Generación de códigos ────────────────────────────────────────────── */
/* Rejilla de PIN recién generados. Sin gap, los chips .v-code se solapan al
   partir en varias líneas (padding 3px contra el line-height del cuerpo). */
#gen-pins{
  display:flex; flex-wrap:wrap; gap:8px;
  max-height:230px; overflow-y:auto;
}
#gen-pins .v-code{ cursor:pointer; border:var(--v-stroke) solid var(--v-line); }
#gen-pins .v-code:hover{ border-color:var(--v-text-2); color:var(--v-text); }
#gen-pins .v-code.is-done{ border-color:var(--v-ok); color:var(--v-ok); }

/* Acciones sueltas bajo un bloque (copiar todo, exportar los PIN del lote). */
.adm-inline-actions{ display:flex; flex-wrap:wrap; gap:10px; align-items:center; }

/* Tabla anidada: las cartas de un usuario, dentro de su fila desplegada.
   Hereda todo de .adm-table; solo hay que soltarle el ancho mínimo, porque
   aquí la caja que hace scroll ya es la de fuera. */
.adm-subtable{ min-width:0; background:var(--v-bg); }
.adm-subtable td{ border-bottom-color:var(--v-line); }

/* Pila vertical con separación propia (resultado de generar un lote). */
.adm-stack{ display:flex; flex-direction:column; gap:var(--s2); }

/* Utilidades de maqueta. Existen para que adminpanel.js no escriba style= en
   línea, que el contrato solo permite para el color de mazo. */
.adm-grow{ flex:1 1 260px; }
.adm-grow-sm{ flex:1 1 180px; }
.adm-qty{ width:110px; }
.adm-note{ margin-top:var(--s2); }
.adm-caption{ margin-bottom:10px; }
.adm-tools-next{ margin-top:var(--s3); }

@media (max-width:620px){
  .adm-nav-in{ border-inline:0; }
  .adm-nav-btn{ padding:12px 14px; font-size:14px; }
  .adm-tools{ flex-direction:column; align-items:stretch; }
}


/* ══ 13 · ESTADOS: CARGANDO · VACÍO · ERROR ═══════════════════════════════ */

/* ── Esqueleto ────────────────────────────────────────────────────────── */
.skel{
  background:var(--v-skel);
  background-image:linear-gradient(90deg,transparent 0,var(--v-skel-hi) 50%,transparent 100%);
  background-size:180% 100%;
  background-repeat:no-repeat;
  animation:v-shimmer 1.35s ease-in-out infinite;
}
@keyframes v-shimmer{ from{ background-position:-60% 0 } to{ background-position:160% 0 } }

.skel-card{ display:block; min-width:0; }
.skel-card .skel-art{ width:100%; aspect-ratio:3/4; }
.skel-card .skel-line{ margin-top:10px; }
.skel-line{ height:12px; width:100%; }
.skel-line.short{ width:52%; }
.skel-line.tiny{ height:10px; width:34%; margin-top:7px; }
.skel-block{ height:120px; width:100%; }
.skel-row{ height:44px; width:100%; margin-bottom:var(--v-stroke); }

/* Cualquier zona con aria-busy oculta su contenido real hasta que llegan
   los datos: el JS solo alterna el atributo, no borra nodos. */
[data-state="loading"] .on-ready,
[data-state="empty"]   .on-ready,
[data-state="error"]   .on-ready{ display:none; }
[data-state="ready"]   .on-loading,
[data-state="empty"]   .on-loading,
[data-state="error"]   .on-loading{ display:none; }
[data-state="ready"]   .on-empty,
[data-state="loading"] .on-empty,
[data-state="error"]   .on-empty{ display:none; }
[data-state="ready"]   .on-error,
[data-state="loading"] .on-error,
[data-state="empty"]   .on-error{ display:none; }

/* ── Vacío / error ────────────────────────────────────────────────────── */
.v-empty,.v-error{
  display:flex; flex-direction:column; align-items:flex-start; gap:var(--s2);
  padding:var(--s5) var(--s4);
  border:var(--v-stroke) dashed var(--v-line);
  background:var(--v-surface-2);
  max-width:62ch;
}
.v-empty h3,.v-error h3{ font-family:var(--display); font-size:21px; line-height:1.1; }
.v-empty p,.v-error p{ color:var(--v-text-2); font-size:16px; }
.v-empty .v-btn,.v-error .v-btn{ margin-top:var(--s1); }
.v-empty-mark{ width:34px; height:34px; background:var(--v-line); clip-path:polygon(var(--chamfer) 0,100% 0,100% calc(100% - var(--chamfer)),calc(100% - var(--chamfer)) 100%,0 100%,0 var(--chamfer)); }

.v-error{ border-style:solid; border-color:var(--v-err); background:var(--v-err-bg); }
.v-error h3{ color:var(--v-err); }
.v-error p{ color:var(--v-text-2); }
.v-error .v-code{ font-family:var(--mono); font-size:12.5px; color:var(--v-text-3); }


/* ══ 14 · TOASTS ══════════════════════════════════════════════════════════ */

.toast-stack{
  position:fixed; z-index:70; right:var(--s3); bottom:var(--s3);
  display:flex; flex-direction:column; gap:10px;
  width:min(370px,calc(100vw - var(--s3) * 2));
  pointer-events:none;
}
.toast{
  display:flex; align-items:flex-start; gap:11px;
  padding:14px 16px;
  background:var(--v-inv-bg); color:var(--v-inv-text);
  border:var(--v-stroke) solid var(--v-inv-line);
  border-left:4px solid var(--v-text-3);
  box-shadow:var(--v-shadow-up);
  font-size:15px; line-height:1.5;
  pointer-events:auto;
  animation:v-toast-in .28s cubic-bezier(.2,.8,.2,1) both;
}
.toast.is-out{ animation:v-toast-out .22s ease both; }
@keyframes v-toast-in{ from{ opacity:0; transform:translateY(14px) } to{ opacity:1; transform:none } }
@keyframes v-toast-out{ to{ opacity:0; transform:translateY(10px) } }
.toast.ok  { border-left-color:#4FD69C; }
.toast.err { border-left-color:#FF8B7A; }
.toast.warn{ border-left-color:var(--gold); }
.toast.info{ border-left-color:#5FCEE4; }
.toast-txt{ min-width:0; }
.toast-close{
  margin-left:auto; flex:0 0 auto;
  width:22px; height:22px; display:flex; align-items:center; justify-content:center;
  color:var(--v-inv-text-3);
}
.toast-close:hover{ color:var(--v-inv-text); }

@media (max-width:560px){
  .toast-stack{ left:var(--s3); right:var(--s3); width:auto; }
}


/* ══ 15 · ACCESIBILIDAD Y PREFERENCIAS ════════════════════════════════════ */

/* styles.css ya fija :focus-visible con --accent-ink. En bloque oscuro ese
   rojo no llega a contraste, así que ahí el foco se dibuja en dorado. */
.auth-art :focus-visible,
.vd-in :focus-visible,
.toast :focus-visible,
.reveal-ov :focus-visible,
.sub-card.is-free :focus-visible{ outline:2.5px solid var(--gold); outline-offset:2px; }

/* Bloquea el scroll del fondo mientras hay una capa modal abierta. */
body.is-locked{ overflow:hidden; }

@media (prefers-contrast:more){
  :root{
    --v-line:#8E94A2; --v-line-soft:#AFB4C0; --v-text-2:#3C4250; --v-text-3:#4C5262;
    --v-stroke:1px; --v-stroke-2:2px;
  }
}

@media (prefers-reduced-motion:reduce){
  .skel{ animation:none; }
  .rv-inner{ animation:none; }
  .auth-deal-inner{ animation:none; }   /* se queda de cara, sin giro */
  .toast{ animation:none; }
  .reveal-ov{ animation:none; }
  .v-btn.is-busy::after{ animation:none; }
  .dc-bar-fill{ transition:none; }
}

/* Impresión: el prompt de una carta es lo único que merece papel. */
@media print{
  .vault-top,.adm-nav,.toast-stack,.vd-actions,.vd-langs,.vd-nav,.vd-close,.vault-foot{ display:none !important; }
  body.app{ background:#FFFFFF; color:#000000; }
  .vd-in{ background:#FFFFFF; border:0; max-height:none; }
  .vd-prompt{ background:#FFFFFF; color:#000000; border-color:#CCCCCC; }
}


/* ══ 16 · PIEZAS SOBRE FONDO OSCURO ═══════════════════════════════════════
   Las primitivas de la sección 4 están calibradas para el fondo claro de la
   aplicación. Dentro del modal de carta, del revelado y del panel de oferta
   —que son bloques oscuros SIEMPRE, en los dos temas— hay que repintarlas o
   aparece una caja blanca flotando en mitad del negro. */

/* Mensajes en línea dentro del modal (error de carga del prompt, aviso de
   permiso denegado). Misma anatomía, superficies invertidas. */
.vd-in .v-msg,
.reveal-ov .v-msg{ background:rgba(255,255,255,.07); color:var(--v-inv-text-2); border-left-color:var(--v-inv-text-3); }
.vd-in .v-msg.ok  { background:rgba(79,214,156,.13);  border-left-color:#4FD69C; color:#8CE8BF; }
.vd-in .v-msg.err { background:rgba(255,139,122,.13); border-left-color:#FF8B7A; color:#FFB3A6; }
.vd-in .v-msg.warn{ background:rgba(245,185,66,.13);  border-left-color:var(--gold); color:#F7CE84; }
.vd-in .v-msg.info{ background:rgba(95,206,228,.13);  border-left-color:#5FCEE4; color:#9BE0EF; }

/* Esqueleto de carga del prompt: sobre negro, un gris claro parpadeando
   deslumbra. Aquí el hueco es apenas más claro que el fondo. */
.vd-in .skel{
  background:rgba(255,255,255,.07);
  background-image:linear-gradient(90deg,transparent 0,rgba(255,255,255,.13) 50%,transparent 100%);
}

/* Carta bloqueada abierta desde la rejilla: en vez del prompt, la razón por la
   que no se ve y la salida (suscribirse o canjear un código). Nunca un modal
   vacío: eso se lee como error, no como muro de pago. */
.vd-locked{
  display:flex; flex-direction:column; align-items:flex-start; gap:var(--s2);
  padding:var(--s5) var(--s4);
  border:var(--v-stroke) dashed var(--v-inv-line);
  background:var(--v-inv-surface);
  max-width:62ch;
}
.vd-locked h3{ font-family:var(--display); font-size:21px; line-height:1.1; color:var(--v-inv-text); }
.vd-locked p{ color:var(--v-inv-text-2); font-size:16px; }
.vd-locked .v-lbl{ color:var(--d,var(--gold)); }
.vd-locked .actions{ display:flex; gap:var(--s2); flex-wrap:wrap; margin-top:var(--s1); }

/* Sobre negro, el hover de .v-btn tira de --v-text/--v-bg: en tema claro eso
   deja un botón oscuro sobre fondo oscuro. Aquí el hover va siempre a blanco. */
.vd-in .v-btn:hover:not(:disabled),
.reveal-ov .v-btn:hover:not(:disabled),
.sub-card.is-free .v-btn:hover:not(:disabled){ background:#FFFFFF; border-color:#FFFFFF; color:#0C0F16; }
.vd-in .v-btn-ghost,
.reveal-ov .v-btn-ghost,
.sub-card.is-free .v-btn-ghost{ color:#FFFFFF; border-color:rgba(255,255,255,.42); }
.vd-in .v-btn.is-busy::after,
.reveal-ov .v-btn.is-busy::after,
.sub-card.is-free .v-btn.is-busy::after{ color:#FFFFFF; }

/* Dato técnico suelto: un PIN recién generado, el código de un error de Auth.
   Existía solo dentro de .v-error; aquí se generaliza para el admin y el login. */
.v-code{
  font-family:var(--mono); font-size:13px; letter-spacing:.08em;
  color:var(--v-text-2); background:var(--v-surface-3);
  padding:3px 7px; white-space:nowrap;
}


/* ══ 17 · PÁGINAS LEGALES (privacy.html · terms.html) ═════════════════════
   Dos páginas PÚBLICAS —sin Firebase y sin sesión— que reutilizan el marco de
   la zona privada: .vault-top arriba, .vault-foot abajo, banderas .fl-es /
   .fl-en y el interruptor de tema. Aquí solo se añade lo que faltaba: el
   cuerpo de un documento de lectura larga.

   Criterios, y por qué:
   · Medida corta: 66-70 caracteres por línea, el tramo en el que el ojo salta
     de renglón sin perderse. La rejilla de 1320px de la bóveda es para
     tarjetas, no para párrafos.
     Ojo con la unidad: `ch` es el ancho del glifo «0», y en Archivo el cero es
     bastante MÁS ancho que la letra media. Medido sobre el texto real de estos
     dos documentos, 68ch daban 86 caracteres por línea, no 68; 54ch dan 68.
     No lo subas «porque se ve estrecho»: se ve estrecho en un monitor de 27
     pulgadas, que no es donde se lee esto.
   · Cero animación y cero reveal al hacer scroll. Un texto con efectos
     jurídicos tiene que estar entero desde el primer pintado, también para
     quien lo imprime o lo lee con un lector de pantalla.
   · La numeración («1.», «2.» …) es parte del TEXTO del <h2>, no un counter de
     CSS: es texto citable, y un contador no se copia al seleccionar.
   · Los dos idiomas viven en el mismo archivo, uno visible cada vez, según el
     lang del <html> que fija el script en línea antes del primer pintado. Sin
     JS se ven LOS DOS, como en el documento original: es preferible leer de
     más que quedarse sin la mitad del contrato.

   Anatomía del HTML, que es lo que explica el reparto de selectores:

     main.vault-main > .vault-in > .legal-wrap
        └─ article.legal-doc[lang]        ← uno por idioma
             ├─ h1 + p.legal-date
             ├─ nav.legal-toc             ← índice: NO hereda el cuerpo
             ├─ section.legal-sec × N     ← el texto legal
             └─ a.legal-back

   Por eso las reglas del cuerpo cuelgan de .legal-sec y no de .legal-doc: si
   colgaran del documento entero, las viñetas cuadradas y el subrayado de los
   enlaces se comerían también el índice.                                    */

/* ── Selección de idioma ──────────────────────────────────────────────── */
/* La clase .js la pone el script en línea del <head>. Sin ella no se oculta
   nada, y por eso el caso sin JS no necesita ningún !important. */
html.js[lang="es"] .legal-doc[lang="en"],
html.js[lang="en"] .legal-doc[lang="es"]{ display:none; }

/* Modo sin JS: los dos documentos, separados por un trazo grueso. */
html.no-js .legal-doc + .legal-doc{
  margin-top:var(--s6);
  padding-top:var(--s6);
  border-top:var(--v-stroke-2) solid var(--v-line);
}

/* ── Armazón ──────────────────────────────────────────────────────────── */
/* El padding lateral sigue viviendo en .vault-in; esto solo estrecha.
   54ch = ~511px a 17px = ~68 caracteres reales. Ver la nota de la cabecera. */
.legal-wrap{ max-width:54ch; min-width:0; }

.legal-doc{
  font-size:17px;
  line-height:1.72;
  /* Un correo o una URL sin espacios no puede sacar barra horizontal a 320px. */
  overflow-wrap:break-word;
}

.legal-doc h1{
  font-family:var(--display);
  font-size:clamp(27px,3.4vw,42px);
  line-height:.98; letter-spacing:-.02em;
  color:var(--v-text);
  margin-bottom:12px;
  text-wrap:balance;
}

/* Fecha de última actualización: es una frase, no un rótulo — nada de
   text-transform:uppercase, que destroza la legibilidad de una fecha. */
.legal-date{
  font-family:var(--mono);
  font-size:13px; letter-spacing:.04em;
  color:var(--v-text-2);
}

/* ── Índice de secciones ──────────────────────────────────────────────── */
.legal-toc{
  margin:var(--s4) 0 var(--s5);
  padding:var(--s3);
  background:var(--v-surface-2);
  border:var(--v-stroke) solid var(--v-line);
  border-left:4px solid var(--accent);
}
.legal-toc h2{
  font-family:var(--mono); font-size:12.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--v-text-2);
  margin-bottom:14px;
}
.legal-toc ol{ list-style:none; display:grid; gap:10px; }
.legal-toc a{
  color:var(--v-text); font-size:16px; line-height:1.4;
  border-bottom:var(--v-stroke) solid transparent;
}
.legal-toc a:hover,
.legal-toc a:focus-visible{ color:var(--v-accent-text); border-bottom-color:currentColor; }

/* ── Secciones ────────────────────────────────────────────────────────── */
.legal-sec{
  margin-top:var(--s5);
  padding-top:var(--s4);
  border-top:var(--v-stroke) solid var(--v-line-soft);
  /* La barra es sticky: sin esto el título aterriza debajo de ella. */
  scroll-margin-top:calc(var(--topbar-h) + var(--s2));
}
.legal-sec:first-of-type{ margin-top:0; }

.legal-sec h2{
  font-family:var(--display);
  font-size:clamp(19px,2vw,23px);
  line-height:1.16; letter-spacing:-.01em;
  color:var(--v-text);
  margin-bottom:14px;
  text-wrap:balance;
}

.legal-sec p{ color:var(--v-text-2); margin-bottom:var(--s2); }
.legal-sec p:last-child{ margin-bottom:0; }
.legal-sec strong{ color:var(--v-text); font-weight:600; }

/* Viñeta cuadrada de la casa: el mismo bloque sólido de .plan li. */
.legal-sec ul{ list-style:none; display:grid; gap:11px; margin-bottom:var(--s2); }
.legal-sec li{ position:relative; padding-left:22px; color:var(--v-text-2); }
.legal-sec li::before{
  content:""; position:absolute; left:0; top:.66em;
  width:8px; height:8px; background:var(--accent);
}

/* En un documento legal el enlace tiene que verse: aquí el subrayado se queda. */
.legal-sec a{
  color:var(--v-accent-text);
  text-decoration:underline; text-underline-offset:3px;
}
.legal-sec a:hover{ color:var(--v-text); }

/* ── Salidas ──────────────────────────────────────────────────────────── */
.legal-back{
  display:inline-block;
  margin-top:var(--s5);
  font-weight:600; font-size:16px;
  color:var(--v-accent-text);
  border-bottom:var(--v-stroke) solid transparent;
}
.legal-back:hover{ border-bottom-color:currentColor; }

.legal-note{
  margin-top:var(--s6);
  padding:14px 16px;
  background:var(--v-surface-2);
  border:var(--v-stroke) solid var(--v-line);
  border-left:4px solid var(--gold);
  color:var(--v-text-2);
  font-size:14.5px; line-height:1.6;
}

/* ── Barra superior en estas dos páginas ──────────────────────────────── */
/* A 320px la fila mide logo + banderas + tema + botón y se sale. El botón es
   lo primero que sobra: el propio logo ya lleva a la portada, y el pie
   repite el enlace. */
@media (max-width:480px){
  .vault-top .vt-btn-home{ display:none; }
}

/* ── Impresión ────────────────────────────────────────────────────────── */
@media print{
  .vault-top,.vault-foot,.legal-toc,.legal-back,.skip{ display:none; }
  .legal-wrap{ max-width:none; }
  .legal-sec{ break-inside:avoid; }
  .legal-sec h2{ break-after:avoid; }
}


/* ══ 18 · MODAL DE CARTA · PESTAÑAS DE PRIMER NIVEL ═══════════════════════
   Añadido para separar el modal en tres secciones —«La carta», «El prompt» e
   «Instalar»— en vez de un único scroll continuo con la instalación perdida
   al final. Complementa la sección 10; no reemplaza nada de ella.

   Todos los colores salen de tokens ya definidos en :root (sección 1) y
   ninguno se define dentro de un media query, como manda la casa. */

/* ── La barra de pestañas ─────────────────────────────────────────────── */
/* Misma anatomía que .vd-langs: filete inferior, filete entre
   botones y el activo en negativo. flex-wrap es la red de seguridad: a 360px
   las tres etiquetas caben en una fila, pero si alguna traducción futura se
   alarga, envuelven en vez de desbordar. */
.vd-nav{
  display:flex; flex-wrap:wrap; align-items:stretch;
  border-bottom:var(--v-stroke) solid var(--v-inv-line);
  flex:0 0 auto;
}
/* flex:1 1 auto reparte el ancho a partes iguales: blancos de pulsación
   mayores y simétricos, que en móvil es lo que decide si se acierta o no. */
.vd-navtab{
  flex:1 1 auto; min-width:0; text-align:center;
  padding:13px 18px;
  font-size:14.5px; font-weight:600; color:var(--v-inv-text-2);
  border-right:var(--v-stroke) solid var(--v-inv-line);
  transition:background .15s,color .15s;
}
.vd-navtab:last-child{ border-right:0; }
.vd-navtab:hover{ background:rgba(255,255,255,.08); color:var(--v-inv-text); }
.vd-navtab.active{ background:var(--v-inv-text); color:var(--v-inv-bg); }

/* ── Los tres paneles ─────────────────────────────────────────────────── */
/* Se enseñan y esconden con .active, NUNCA con [hidden]: mismo patrón que
   .vd-way, y así no se depende de que [hidden]{display:none !important}
   (línea 187) gane contra un display de autor. */
.vd-pane{ display:none; min-width:0; }
.vd-pane.active{ display:block; }
.vd-pane > * + *{ margin-top:var(--s2); }
.vd-pane > p{ font-size:15.5px; line-height:1.6; color:var(--v-inv-text-2); max-width:62ch; }

/* .vd-install ya no va detrás del prompt: su filete de separación sobra. */
.vd-pane > .vd-install{ margin-top:0; border-top:0; padding-top:0; }

/* ── Ficha de la carta ────────────────────────────────────────────────── */
/* OJO CON LA ESPECIFICIDAD, que aquí muerde: `.vd-pane > p` puntúa 0-1-1 y
   ganaría a `.vd-lede` (0-1-0) y a `.v-lbl` (0-1-0), dejando la entradilla a
   15,5px y convirtiendo el rótulo mono en un párrafo normal. Por eso las dos
   se escriben calificadas —0-2-1— en vez de a secas. No las simplifiques. */
.vd-pane > p.vd-lede{
  font-size:17px; line-height:1.55; color:var(--v-inv-text); max-width:58ch;
}
.vd-pane > p.v-lbl{
  font-family:var(--mono); font-size:12.5px; line-height:1.4;
  letter-spacing:.12em; text-transform:uppercase;
  color:var(--v-inv-text-3); max-width:none;
}

/* .v-lbl está calibrada para el fondo claro de la aplicación (sección 4): en
   el modal hay que repintarla o queda gris oscuro sobre negro.
   Se acota a .vd-pane y NO a .vd-in a propósito: `.vd-in .v-lbl` puntúa igual
   que `.vd-locked .v-lbl` (sección 16) y, al ir después en el archivo, le
   robaría el dorado al rótulo del muro de pago. */
.vd-pane .v-lbl{ color:var(--v-inv-text-3); }

.vd-facts{ display:flex; flex-wrap:wrap; gap:var(--s1) var(--s3); }
.vd-fact{ display:flex; align-items:center; gap:8px; min-width:0; }

/* Muro de pago, error o carta sin prompt: van DEBAJO de la ficha, dentro del
   mismo cuerpo y sin barra de pestañas. Necesitan su aire. */
.vd-body > .vd-pane + *{ margin-top:var(--s4); }

/* ── Instalación nativa, ahora dentro de su sub-pestaña ───────────────── */
/* Dentro del panel, .vd-hint ya no es una franja del cromo: pierde su padding
   lateral y su filete, que ahí duplicarían el borde del propio panel.
   El tamaño se declara a posta. Al ser un <p> hijo directo del panel,
   `.vd-way > p` (0-1-1) le ganaba a `.vd-hint` (0-1-0) y lo subía de
   14px a 15,5px por accidente. Se queda en 15,5px —ahora ES el párrafo de
   entrada de su pestaña, como el de las otras cuatro— pero escrito en vez de
   heredado, para que no dependa de que nadie reordene el archivo. */
.vd-way .vd-hint{
  padding:0; border-bottom:0;
  font-size:15.5px; line-height:1.6; color:var(--v-inv-text-2);
}
.vd-native-row{
  display:flex; flex-wrap:wrap; align-items:stretch;
  border:var(--v-stroke) solid var(--v-inv-line);
  margin-block:var(--s2);
}
.vd-native-row .vd-act:last-child{ border-right:0; }

/* Mientras el prompt viaja, los botones de copiar de los bloques de código
   salen inertes: sin prompt copiarían la nada. .vd-act ya tenía su :disabled
   en la sección 10; .vd-copy no. */
.vd-copy:disabled{ opacity:.45; cursor:not-allowed; }
.vd-copy:disabled:hover{ background:transparent; color:var(--v-inv-text-2); }

@media (max-width:620px){
  /* 13,5px: por encima del suelo de 12,5px de la casa, nunca por debajo. */
  .vd-navtab{ padding:13px 12px; font-size:13.5px; }
}

/* ── Impresión ────────────────────────────────────────────────────────── */
/* El prompt de una carta sigue siendo lo único que merece papel, pero ahora
   vive dentro de un panel que puede estar en display:none. Si el usuario
   pulsa Ctrl+P estando en «Instalar» —camino que no pasa por actPdf()— la
   hoja saldría en blanco. Aquí se fuerza el panel del prompt pase lo que
   pase, y se apartan los otros dos. */
@media print{
  #vd-pane-card,#vd-pane-install{ display:none !important; }
  #vd-pane-prompt{ display:block !important; }
}
