/* ═══════════════════════════════════════════════════════════════════════════
   Hub de Conocimiento VITTA — sistema de diseño
   Extraído del prototipo `Hub Aula Vitta Retail.dc.html`. Los valores no son
   aproximaciones: son los mismos del original.
   ═══════════════════════════════════════════════════════════════════════════ */

/*
 * TOKENS
 *
 * Ninguna vista debe volver a escribir un `#hex`. Si un color no está acá, no
 * existe. Los nombres son semánticos a propósito (`--v-surface`, no
 * `--v-blanco`): es lo que permite que el modo oscuro sea un remapeo de 20
 * líneas en vez de una segunda hoja de estilos.
 */
:root {
  color-scheme: light;

  /* Verdes de marca — son identidad, no varían con el tema */
  --v-deep:      #0C3B36;  /* fondo del sidebar y las tarjetas oscuras */
  --v-deep-2:    #14524A;  /* segundo tono del degradado */
  --v-green:     #14A07A;  /* acento principal, acciones */
  --v-green-2:   #0B6B58;  /* estados certificados */
  --v-green-3:   #0E8161;  /* hover de enlaces */
  --v-line-dark: #1E635A;  /* separadores sobre fondo oscuro */
  --v-lime:      #8ACE2A;  /* el verde claro del logotipo: «RETAIL», la barra
                              del splash y el arco que se dibuja alrededor del
                              disco. Estaba escrito a mano en cuatro lugares. */

  /* Texto */
  --v-ink:     #10302B;
  --v-ink-2:   #5C6B67;
  --v-muted:   #7E938E;
  --v-muted-2: #A6BAB4;
  --v-on-deep:      #FFFFFF;  /* texto sobre superficies verde profundo */
  --v-on-deep-soft: #BFD1CC;  /* texto secundario sobre verde profundo */

  /* Superficies */
  --v-bg:      #F4F7F5;
  --v-surface: #FFFFFF;
  --v-border:  #DDE7E3;
  --v-fill:    #E7EEEB;
  --v-fill-2:  #E9F0ED;
  --v-fill-3:  #F2FAF7;  /* casilla marcada, realce suave */

  /* Estados */
  --v-ok-bg:     #E1EFE9;
  --v-mine-bg:   #E4F4EE;  /* fila propia del ranking, lección activa, tag «Nuevo» */
  --v-ok-fg:     #0B6B58;
  --v-warn-bg:   #FBF1D8;
  --v-warn-fg:   #A8790F;
  --v-warn-solid:#C98A14;
  --v-danger-bg: #FBEAEA;
  --v-danger-fg: #A32020;
  --v-danger-border: #F0C9C9;
  --v-info-bg:   #E6EFF6;
  --v-info-fg:   #1F5F8B;
  --v-teams:     #4B53BC;

  /* Tipos de documento del banco */
  --v-type-pdf:      #14A07A;
  --v-type-video:    #5C6B67;
  --v-type-onepager: #1F5F8B;
  --v-type-vr360:    #0B6B58;
  --v-type-tool:     #8A5A3C;
  --v-type-link:     #7E938E;

  /* Gris del visor nativo de PDF de Chrome y Edge. La caja que envuelve al
     iframe lo copia para que no se vea un marco claro alrededor del documento
     mientras carga. No se remapea en oscuro: es el color del visor, no nuestro. */
  --v-visor-bg: #525659;

  /* Sombras y velos — tokenizados porque en oscuro un negro al 18 % desaparece */
  --v-shadow-sm:  0 2px 8px rgba(0, 0, 0, .18);
  --v-shadow-md:  0 8px 24px rgba(12, 59, 54, .10);
  --v-shadow-lg:  0 16px 50px rgba(0, 0, 0, .22);
  --v-scrim:      rgba(16, 26, 36, .5);
  --v-ring:       rgba(20, 160, 122, .16);
  /* Arranque del halo que late en la puerta al canje. Va como token y no
     suelto en la animación por la misma razón que `--v-ring`: es el verde de
     marca con opacidad, y el día que la marca cambie de verde tiene que
     cambiar acá también y no en un `@keyframes` perdido a mitad de la hoja. */
  --v-halo-canje: rgba(20, 160, 122, .38);
  --v-scrollbar:  #C9D8D3;
  /* Aro del avatar. Es un color FIJO metido en una superficie TEMÁTICA —el
     encabezado—, así que tiene que ser token: en claro separa la foto del
     blanco, en oscuro un blanco al 90 % se convierte en un halo que grita. */
  --v-avatar-ring: rgba(255, 255, 255, .9);

  --v-radius:    14px;
  --v-radius-sm: 10px;

  /* Escala de espaciado. Cuatro valores, no doce: las vistas venían usando
     10/12/14/16/18/22/24/26/28/30 px sin criterio, y esa dispersión es
     precisamente lo que hace que dos tarjetas nunca se vean hermanas. */
  --v-sp-1: 6px;
  --v-sp-2: 10px;
  --v-sp-3: 14px;
  --v-sp-4: 18px;
  --v-sp-5: 24px;
  --v-sp-6: 32px;
}

/*
 * MODO OSCURO
 *
 * En tienda con luz baja —bodega, depósito, apertura antes del amanecer— un
 * fondo #F4F7F5 a pantalla completa encandila. Se respeta la preferencia del
 * sistema y se deja override manual con `data-theme` para quien la quiera fija.
 *
 * Los verdes de marca NO se tocan: el sidebar sigue siendo el sidebar. Lo que
 * se remapea son las superficies claras y el texto que va sobre ellas.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --v-ink:     #E8F1EE;
    --v-ink-2:   #A9BEB8;
    --v-muted:   #8AA39D;
    --v-muted-2: #6E8781;

    --v-bg:      #0A1917;
    --v-surface: #122622;
    --v-border:  #24413A;
    --v-fill:    #1B322D;
    --v-fill-2:  #1E3831;
    --v-fill-3:  #16332B;

    --v-deep:    #081F1C;
    --v-deep-2:  #103A34;

    --v-ok-bg:     #10352C;
    --v-mine-bg:   #133D32;
    --v-ok-fg:     #6FD2AE;
    --v-warn-bg:   #3A2E12;
    --v-warn-fg:   #E5B54B;
    --v-danger-bg: #3A1A1A;
    --v-danger-fg: #F09A9A;
    --v-danger-border: #5C2A2A;
    --v-info-bg:   #162C3C;
    --v-info-fg:   #8FC2E8;

    --v-shadow-sm: 0 2px 8px rgba(0, 0, 0, .5);
    --v-shadow-md: 0 8px 24px rgba(0, 0, 0, .45);
    --v-shadow-lg: 0 16px 50px rgba(0, 0, 0, .6);
    --v-scrim:     rgba(0, 0, 0, .66);
    --v-scrollbar: #2C4B43;
    --v-avatar-ring: rgba(255, 255, 255, .22);
  }
}

/* Override manual: gana sobre la preferencia del sistema, en los dos sentidos. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --v-ink:     #E8F1EE;
  --v-ink-2:   #A9BEB8;
  --v-muted:   #8AA39D;
  --v-muted-2: #6E8781;

  --v-bg:      #0A1917;
  --v-surface: #122622;
  --v-border:  #24413A;
  --v-fill:    #1B322D;
  --v-fill-2:  #1E3831;
  --v-fill-3:  #16332B;

  --v-deep:    #081F1C;
  --v-deep-2:  #103A34;

  --v-ok-bg:     #10352C;
  --v-mine-bg:   #133D32;
  --v-ok-fg:     #6FD2AE;
  --v-warn-bg:   #3A2E12;
  --v-warn-fg:   #E5B54B;
  --v-danger-bg: #3A1A1A;
  --v-danger-fg: #F09A9A;
  --v-danger-border: #5C2A2A;
  --v-info-bg:   #162C3C;
  --v-info-fg:   #8FC2E8;

  --v-shadow-sm: 0 2px 8px rgba(0, 0, 0, .5);
  --v-shadow-md: 0 8px 24px rgba(0, 0, 0, .45);
  --v-shadow-lg: 0 16px 50px rgba(0, 0, 0, .6);
  --v-scrim:     rgba(0, 0, 0, .66);
  --v-scrollbar: #2C4B43;
  --v-avatar-ring: rgba(255, 255, 255, .22);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* `hidden` debe ganarle a cualquier `display` de componente: es el interruptor
   de los diálogos y no puede depender del orden de las reglas. */
[hidden] { display: none !important; }

body {
  font-family: 'Karla', system-ui, sans-serif;
  color: var(--v-ink);
  background: var(--v-bg);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--v-green); text-decoration: none; }
a:hover { color: var(--v-green-3); }
input, button, select, textarea { font-family: inherit; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb {
  background: var(--v-scrollbar); border-radius: 8px; border: 2px solid var(--v-bg);
}

/* ── Foco visible ────────────────────────────────────────────────────────────
 * Antes de esto, el único `:focus` de toda la hoja estaba en `.v-input`.
 * Navegar con teclado era navegar a ciegas: el foco existía pero no se veía.
 *
 * `:focus-visible` y no `:focus`: el aro aparece para quien navega con teclado
 * y no cada vez que alguien toca un botón con el dedo.
 */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--v-green);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Sobre el sidebar y las tarjetas oscuras el verde de marca no despega del
   fondo. Ahí el aro se dibuja en blanco. */
.v-sidebar :where(a, button):focus-visible,
.v-card-dark :where(a, button):focus-visible,
.v-card-gradient :where(a, button):focus-visible,
.v-drawer-head :where(a, button):focus-visible {
  outline-color: #fff;
}
/* Los controles con radio propio no deben recuadrarse con esquinas rectas. */
.v-btn:focus-visible, .v-chip:focus-visible { border-radius: var(--v-radius-sm); }
.v-badge:focus-visible, .v-phase-chip:focus-visible, .v-filter:focus-visible { border-radius: 99px; }

/* ── Salto al contenido ──────────────────────────────────────────────────────
 * Sin esto, llegar al contenido con teclado cuesta ~12 tabulaciones por el
 * menú lateral, en TODAS las páginas.
 */
.v-skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--v-deep); color: #fff; padding: 13px 20px;
  border-radius: 0 0 var(--v-radius-sm) 0; font-weight: 700; font-size: 14px;
}
.v-skip:focus {
  left: 0; color: #fff;
}

/* El destino del salto no debe mostrar aro: no es un control, sólo un ancla. */
.v-content:focus { outline: none; }

/* ── Texto sólo para lector de pantalla ──────────────────────────────────────
 * Hay diferencias que la pantalla comunica con color o con gris: la fila propia
 * del ranking pintada de verde, la insignia todavía no obtenida al 50 % de
 * opacidad. Para quien no ve la pantalla, esa diferencia sencillamente no
 * existe. Acá se la dice con palabras, sin ocupar un píxel.
 */
.v-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

@keyframes erFade   { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes erDrawer { from { transform: translateX(100%); } to { transform: none; } }
@keyframes erPop    { from { opacity: 0; transform: scale(.96); } to { opacity: 1; transform: none; } }

/* Pantalla de carga — mismas curvas y tiempos que el prototipo. */
@keyframes vSplashOut { 0%, 78% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
@keyframes vLeafIn    { 0% { opacity: 0; transform: translate(6px, -8px) rotate(-12deg) scale(.85); } 100% { opacity: 1; transform: none; } }
@keyframes vBagIn     { 0% { opacity: 0; transform: translateY(14px); } 100% { opacity: 1; transform: none; } }
@keyframes vRise      { 0% { opacity: 0; transform: translateY(12px); } 100% { opacity: 1; transform: none; } }
@keyframes vBar       { 0% { transform: translateX(-100%); } 100% { transform: translateX(0); } }
@keyframes vBreath    { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.035); } }

/* Quien pidió menos movimiento no debería recibir una animación de 2,4 s. */
@media (prefers-reduced-motion: reduce) {
  #v-splash { animation: none !important; opacity: 0; visibility: hidden; }
  #v-splash * { animation: none !important; }
  /* El arco se dibuja con una animación: sin ella se quedaría invisible. */
  .v-splash-arc { stroke-dashoffset: 0; }
}

/* Avatar con foto. Circular, como el prototipo. */
.v-avatar {
  border-radius: 50%; object-fit: cover; object-position: center top;
  flex: 0 0 auto; display: block; background: var(--v-fill);
  /* Aro fino para separar la foto del fondo: sin él, una foto de fondo claro
     sobre el sidebar oscuro se ve como un recorte flotando. Va por token
     porque el avatar del encabezado se apoya en una superficie que SÍ cambia
     con el tema: el mismo blanco al 90 % que en claro apenas se nota, en
     oscuro se lee como un halo alrededor de la cara. */
  border: 2px solid var(--v-avatar-ring);
  box-shadow: var(--v-shadow-sm);
}
/* El sidebar es verde profundo en los dos temas, así que este aro NO se
   remapea: siempre se apoya sobre oscuro. */
.v-avatar-dark { border-color: rgba(255, 255, 255, .22); }

/* Vity va SIN aro. Es un robot claro sobre disco claro, así que el borde
   blanco no aporta contraste: sobre las superficies oscuras se lee como un
   halo alrededor de la carita. La imagen ya trae su propio disco. */
/*
 * Vity va SIN disco. El PNG tiene alfa real: el fondo crema que traía horneado
 * se recortó por difusión desde los bordes, respetando el casco blanco del
 * robot —que un recorte por color se habría comido—. El original quedó en
 * `vity-avatar-original.png`.
 *
 * Nada de `border-radius` acá: ya no hay disco que redondear y un círculo
 * cortaría las orejas y el cuello, que llegan al borde del lienzo.
 */
.v-vity {
  object-fit: contain; flex: 0 0 auto;
  display: block; border: none; box-shadow: none; background: none;
}
/*
 * Iniciales sobre disco verde, para quien todavía no subió foto.
 *
 * El fondo es `--v-green-2` y NO `--v-green`, y la diferencia la encontró
 * `ContrasteHeaderTest` calculando: blanco sobre `--v-green` (#14A07A) da
 * **3,31:1**, por debajo del 4,5:1 que exige un texto de 14 px. Con
 * `--v-green-2` (#0B6B58) sube a 6,44:1 sin salirse de la paleta de marca.
 *
 * Las iniciales son texto, no adorno: son la única pista de a quién pertenece
 * la cuenta abierta cuando la tablet se comparte entre turnos.
 *
 * ⚠️ El mismo par blanco/`--v-green` está en otras ocho reglas, `.v-btn-primary`
 * entre ellas. No se toca acá: cambiar el acento principal es una decisión de
 * marca, no un arreglo de encabezado. Queda reportado.
 */
.v-avatar-fallback {
  border-radius: 50%; flex: 0 0 auto; background: var(--v-green-2); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 800;
}

/* Escala de avatar. Los tamaños venían escritos a mano en el atributo `style`
   —40, 38, 26, 50— y ninguno era el mismo dos veces por casualidad: eran el
   mismo tamaño escrito cuatro veces. `.v-avatar-lg` (76 px) vive con el resto
   de la ficha de cuenta. */
.v-avatar-xs { width: 26px; height: 26px; font-size: 10px; }
.v-avatar-sm { width: 38px; height: 38px; font-size: 14px; }
.v-avatar-md { width: 40px; height: 40px; font-size: 14px; }
/* Vity a dos escalas: el ítem del menú y la cabecera del cajón. El margen
   negativo lo compensa dentro de la fila de navegación, que es más baja. */
.v-vity-xs { width: 26px; height: 26px; margin: -3px 0; }
.v-vity-md { width: 50px; height: 50px; }
/* Un enlace que sólo envuelve una imagen: sin esto el `line-height` heredado
   le agrega unos píxeles fantasma debajo de la foto. */
.v-avatar-link { display: block; line-height: 0; }
.v-block { display: block; }
/* Las burbujas del cajón traen párrafos: el margen del navegador les abre un
   hueco arriba que rompe el globo. Se apaga acá y no en cada `<p>`, porque
   varios los escribe el JS al recibir la respuesta. */
.v-msg-bot > p, .v-msg-user > p { margin: 0; }
.v-msg-bot > p + p, .v-msg-bot > p:not(:last-child) { margin-bottom: 10px; }

/* ── Tipografía de titulares ─────────────────────────────────────────────── */
.v-kicker {
  font-family: 'Archivo', sans-serif; font-size: 12px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--v-green); font-weight: 700; margin-bottom: 6px;
}
.v-h1 { font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 34px; text-transform: uppercase; margin: 0; }
.v-h1-lg { font-size: 38px; line-height: 1; }
/* Cuatro pasos de titular, no ocho. Las fichas de documento, el visor y la
   verificación pública venían con 30, 28 y 24 px escritos a mano en la vista:
   tres tamaños distintos para el mismo nivel jerárquico. */
.v-h1-sm { font-size: 28px; line-height: 1.1; }
.v-h1-xs { font-size: 24px; line-height: 1.15; }
.v-h2 { font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 19px; text-transform: uppercase; margin: 0; }
.v-h3 { font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 17px; text-transform: uppercase; margin: 0; }
.v-lead { margin: 10px 0 0; font-size: 15px; color: var(--v-ink-2); max-width: 820px; }

/* ── Estructura ──────────────────────────────────────────────────────────── */
.v-shell { display: flex; min-height: 100vh; width: 100%; background: var(--v-bg); }

.v-sidebar {
  width: 264px; flex: 0 0 auto; background: var(--v-deep);
  display: flex; flex-direction: column; padding: 26px 18px;
  position: sticky; top: 0; height: 100vh;
}
.v-brand { padding: 4px 10px 26px; }
.v-brand-link { display: flex; align-items: center; gap: 13px; }
.v-brand-mark {
  width: 56px; height: 56px; flex: 0 0 auto; border-radius: 50%; background: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
}
.v-brand-mark img { display: block; }
.v-brand-name {
  display: block; font-family: 'Poppins', sans-serif; font-weight: 700;
  font-size: 24px; color: #fff; line-height: 1;
}
.v-brand-sub {
  display: block; font-family: 'Poppins', sans-serif; font-weight: 600;
  font-size: 9px; letter-spacing: .42em; color: var(--v-lime); margin-top: 3px;
}
.v-brand-rule { width: 20px; height: 2px; background: var(--v-green); flex: 0 0 auto; }
.v-brand-tag {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 10px;
  letter-spacing: .24em; text-transform: uppercase; color: var(--v-muted);
}

.v-nav { display: flex; flex-direction: column; gap: 4px; }
/* El botón de Vity comparte todo con los enlaces menos el elemento: se estilan
   juntos para que nadie note la diferencia salvo el teclado, que sí debe. */
.v-nav a, .v-nav-action {
  display: flex; align-items: center; gap: 12px; padding: 11px 14px;
  border-radius: var(--v-radius-sm); font-size: 14px; font-weight: 600;
  color: var(--v-muted); transition: background .15s, color .15s;
}
.v-nav-action {
  background: none; border: none; width: 100%; text-align: left;
  font-family: inherit; cursor: pointer;
}
.v-nav a:hover, .v-nav-action:hover { background: rgba(255, 255, 255, .06); color: #fff; }
/* Verde profundo + barra interna, como el prototipo. Un bloque verde sólido
   pesa demasiado y compite con el acento de las acciones. */
.v-nav a.is-active {
  background: var(--v-deep-2); color: #fff; font-weight: 700;
  box-shadow: inset 3px 0 0 var(--v-green);
}
.v-nav a.is-active:hover { background: var(--v-deep-2); color: #fff; }
.v-nav-tag {
  margin-left: auto; font-family: 'Archivo', sans-serif; font-size: 10px;
  font-weight: 700; letter-spacing: .08em; background: var(--v-green);
  color: #fff; padding: 2px 7px; border-radius: 6px;
}
.v-nav-sep { height: 1px; border: none; background: var(--v-line-dark); margin: 14px 6px 10px; }

.v-sidebar-foot {
  margin-top: auto; border-top: 1px solid var(--v-line-dark); padding-top: 16px;
  display: flex; align-items: center; gap: 12px;
}
.v-sidebar-name { display: block; font-size: 13px; font-weight: 700; color: #fff; }
.v-sidebar-role { display: block; font-size: 11px; color: var(--v-muted); }
.v-sidebar-out { color: var(--v-muted); flex: 0 0 auto; }
.v-sidebar-out:hover { color: #fff; }

.v-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/*
 * El encabezado es una SUPERFICIE, no un rectángulo blanco.
 *
 * Acá decía `background: #fff` y era el único color fijo que quedaba en la
 * barra superior. El efecto medido en producción: en tema claro el header era
 * `rgb(255,255,255)` y el cuerpo `rgb(244,247,245)` —coherente—; al pasar a
 * oscuro el cuerpo se iba a `rgb(10,25,23)` y el header **se quedaba en blanco
 * puro**, flotando sobre una aplicación negra. No es un detalle: es la primera
 * franja que se ve al entrar y la que sostiene el título, el buscador y el
 * avatar.
 *
 * `--v-surface` es el token que ya remapea (#FFFFFF → #122622): es la misma
 * superficie que usan las tarjetas, y el encabezado es exactamente eso.
 */
.v-header {
  height: 74px; flex: 0 0 auto; background: var(--v-surface); border-bottom: 1px solid var(--v-border);
  display: flex; align-items: center; gap: 20px; padding: 0 34px; position: sticky; top: 0; z-index: 20;
}
.v-page-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 21px;
  text-transform: uppercase; letter-spacing: .02em;
}
.v-content { flex: 1; overflow-y: auto; padding: 36px 40px 56px; }
.v-container { max-width: 1240px; margin: 0 auto; animation: erFade .3s ease; }
.v-container-narrow { max-width: 1040px; margin: 0 auto; animation: erFade .3s ease; }

/* ── Tarjetas ────────────────────────────────────────────────────────────── */
.v-card {
  background: var(--v-surface); border: 1px solid var(--v-border);
  border-radius: var(--v-radius); padding: 24px 26px;
}
.v-card-dark { background: var(--v-deep); color: #fff; border: none; border-radius: var(--v-radius); padding: 24px 26px; }
.v-card-gradient {
  background: linear-gradient(135deg, var(--v-deep) 0%, var(--v-deep-2) 100%);
  color: #fff; border: none; border-radius: var(--v-radius); padding: 28px 30px;
}

.v-kpi-label {
  font-family: 'Archivo', sans-serif; font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--v-muted); font-weight: 700;
}
.v-kpi-value {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 56px;
  line-height: 1; margin: 10px 0 2px; letter-spacing: -2px;
}
.v-kpi-note { font-size: 13px; color: var(--v-ink-2); }

/* ── Barras de progreso ──────────────────────────────────────────────────── */
.v-bar { height: 8px; background: var(--v-fill); border-radius: 99px; overflow: hidden; }
.v-bar-sm { height: 6px; }
.v-bar > span { display: block; height: 100%; background: var(--v-green); border-radius: 99px; }
/* El color comunica el estado sin leer la etiqueta. */
.v-bar.is-certified > span { background: var(--v-green-2); }
.v-bar.is-progress  > span { background: var(--v-warn-solid); }
.v-bar.is-locked    > span { background: var(--v-muted-2); }

/* ── Insignias de estado ─────────────────────────────────────────────────── */
.v-badge {
  font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 99px;
  display: inline-block; white-space: nowrap;
}
.v-badge-ok      { color: var(--v-ok-fg);     background: var(--v-ok-bg); }
.v-badge-warn    { color: var(--v-warn-fg);   background: var(--v-warn-bg); }
.v-badge-danger  { color: var(--v-danger-fg); background: var(--v-danger-bg); }
.v-badge-info    { color: var(--v-info-fg);   background: var(--v-info-bg); }
.v-badge-muted   { color: var(--v-muted);     background: var(--v-fill); }
.v-badge-progress{ color: #fff;               background: var(--v-warn-solid); }

/* ── Botones ─────────────────────────────────────────────────────────────── */
.v-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  border: none; border-radius: var(--v-radius-sm); padding: 13px 22px;
  font-size: 14px; font-weight: 800; cursor: pointer; transition: filter .15s;
}
.v-btn:hover { filter: brightness(1.06); }
.v-btn-primary { background: var(--v-green); color: #fff; }
.v-btn-primary:hover { color: #fff; }
.v-btn-dark { background: var(--v-deep); color: #fff; }
.v-btn-dark:hover { color: #fff; }
/*
 * Botón claro sobre una superficie oscura FIJA (la tarjeta de Vity, el visor).
 *
 * Los dos valores son fijos a propósito. Cuando el fondo era `#fff` y el texto
 * `var(--v-ink)`, en modo oscuro el token se remapeaba a un color claro y el
 * botón quedaba blanco sobre blanco: contraste 1.05:1, invisible. Mezclar un
 * color fijo con uno temático en la misma regla es exactamente así como se
 * rompe.
 */
.v-btn-light { background: #FFFFFF; color: #10302B; }
.v-btn-light:hover { color: #10302B; }
.v-btn-ghost { background: var(--v-fill); color: var(--v-ink-2); }
.v-btn-teams { background: var(--v-teams); color: #fff; font-weight: 700; }
.v-btn-teams:hover { color: #fff; }
.v-btn:disabled { opacity: .5; cursor: not-allowed; filter: none; }
/* Acción de retirada: «Ya no voy», «Cancelar». Sin fondo y con el peso de un
   enlace, para que no compita con la acción que la pantalla sí quiere ofrecer
   —anotarse, unirse—. No es `v-btn-danger`: darse de baja de una reunión no es
   destructivo ni irreversible, y pintarlo de rojo asustaría de una decisión
   que se puede deshacer con un clic. */
.v-btn-quiet {
  background: none; color: var(--v-muted); font-weight: 700;
  text-decoration: underline; text-underline-offset: 3px;
}
.v-btn-quiet:hover { color: var(--v-ink-2); }
.v-btn-sm { padding: 9px 16px; font-size: 13px; }

/* ── Grillas ─────────────────────────────────────────────────────────────── */
.v-grid { display: grid; gap: 18px; }
.v-grid-2 { grid-template-columns: repeat(2, 1fr); }
.v-grid-3 { grid-template-columns: repeat(3, 1fr); }
.v-grid-4 { grid-template-columns: repeat(4, 1fr); }
.v-grid-5 { grid-template-columns: repeat(5, 1fr); }

/* ── Encabezado de sección numerada ──────────────────────────────────────── */
.v-section-head { display: flex; align-items: center; gap: 12px; margin: 38px 0 16px; }
.v-section-num { font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 22px; color: var(--v-green); }
.v-section-rule { height: 1px; background: var(--v-border); flex: 1; }
.v-section-note { font-size: 13px; color: var(--v-muted); font-weight: 700; }

/* ── Tarjeta de fase del método ──────────────────────────────────────────── */
.v-phase {
  display: flex; flex-direction: column; background: var(--v-surface);
  border: 1px solid var(--v-border); border-radius: 13px; padding: 20px 22px;
  cursor: pointer; transition: transform .15s, box-shadow .15s;
  /* Altura pareja entre las 5 fases: sin esto, la de descripción más corta
     queda notoriamente más baja y la fila se ve rota. */
  min-height: 230px;
}
.v-phase:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(12, 59, 54, .10); }
.v-phase.is-locked { opacity: .72; cursor: not-allowed; }
.v-phase.is-locked:hover { transform: none; box-shadow: none; }
/* La letra de la fase es el ancla visual de la tarjeta: en verde cuando la fase
   está a mano, apagada cuando todavía no se puede entrar. El color lo decide la
   tarjeta, no la vista: es estado, no dato. */
.v-phase-letter {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 52px;
  line-height: .85; color: var(--v-green);
}
.v-phase.is-locked .v-phase-letter { color: var(--v-muted-2); }
/* El nombre de la fase, debajo de la letra.
   `min-width: 0` en la columna porque el contenedor es un flex: sin eso, un
   nombre largo como «Transforma» empuja la insignia de estado fuera de la
   tarjeta en vez de partirse. */
.v-phase-mark { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.v-phase-name {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 12px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--v-ink-2);
  line-height: 1.1; overflow-wrap: anywhere;
}
.v-phase.is-locked .v-phase-name { color: var(--v-muted-2); }
/* Márgenes negativos para que la foto toque los bordes de la tarjeta. */
.v-phase-thumb {
  height: 96px; background-size: cover; background-position: center;
  margin: -20px -22px 14px; border-radius: 12px 12px 0 0;
}

/* ── Formularios ─────────────────────────────────────────────────────────── */
/* Única definición de `.v-field` y `.v-input` de toda la hoja. */
.v-form-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 22px; }
.v-form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.v-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; margin-bottom: 16px; }
/* Dentro de una grilla el espacio ya lo pone el `gap`: sumarle margen deja el
   doble de aire entre filas y la mitad del previsto en la última. */
.v-form-grid > .v-field, .v-toggle-grid > .v-field { margin-bottom: 0; }
/* Campo que ocupa la fila entera de la grilla —«contraseña actual» antes de las
   dos nuevas—. Era un `style="grid-column:1/-1"` inline, que además obligaba a
   escribir un selector `[style*=…]` para poder anularlo en celular. */
.v-field-wide { grid-column: 1 / -1; }
.v-field-label {
  font-family: 'Archivo', sans-serif; font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--v-ink-2);
}
.v-field-hint { font-size: 12px; color: var(--v-ink-2); line-height: 1.4; }
.v-input {
  width: 100%; padding: 12px 15px; border: 1px solid var(--v-border);
  border-radius: var(--v-radius-sm);
  font-family: inherit; font-size: 14.5px; color: var(--v-ink); background: var(--v-surface);
  transition: border-color .15s, box-shadow .15s;
}
.v-input:focus { outline: none; border-color: var(--v-green); box-shadow: 0 0 0 3px var(--v-ring); }
.v-input::placeholder { color: var(--v-muted-2); }
.v-readonly {
  padding: 12px 15px; border: 1px dashed var(--v-border); border-radius: var(--v-radius-sm);
  font-size: 14.5px; color: var(--v-ink-2); background: var(--v-surface);
}

/* Casillas con área de toque completa: en piso de venta se marca con el pulgar,
   no con el puntero sobre un cuadradito de 13 px. */
.v-toggle-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.v-toggle-grid-1 { grid-template-columns: 1fr; }
.v-toggle {
  display: flex; align-items: center; gap: 13px; padding: 14px 16px; cursor: pointer;
  border: 1px solid var(--v-border); border-radius: 12px; background: #fff;
  transition: border-color .15s, background .15s;
}
.v-toggle:has(input:checked) { border-color: var(--v-green); background: #F2FAF7; }
.v-toggle:has(input:disabled) { opacity: .55; cursor: not-allowed; }
.v-toggle input { width: 19px; height: 19px; flex: 0 0 auto; accent-color: var(--v-green); cursor: inherit; }
.v-toggle-emoji { font-size: 20px; flex: 0 0 auto; }
.v-toggle-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.v-toggle-text strong { font-size: 14px; color: var(--v-ink); }
.v-toggle-text small { font-size: 12px; color: var(--v-ink-2); line-height: 1.35; }

@media (max-width: 680px) {
  .v-form-grid, .v-toggle-grid { grid-template-columns: 1fr; }
  .v-field-wide { grid-column: auto; }
  .v-input { padding: 13px 14px; font-size: 16px; }  /* 16px: iOS no hace zoom. */
}

/* ── Evaluación práctica ─────────────────────────────────────────────────── */
.v-practica { padding: 38px 40px; max-width: 860px; margin: 0 auto; }

.v-practica-head { display: flex; align-items: center; gap: 20px; margin-bottom: 30px; }
.v-practica-icon {
  width: 72px; height: 72px; flex: 0 0 auto; border-radius: 20px;
  background: linear-gradient(140deg, #E1EFE9, #CFE6DC);
  display: flex; align-items: center; justify-content: center; font-size: 36px;
}

/* Los tres pasos: numerados, porque el orden importa y sin número se leen
   como tres opciones sueltas en vez de como un recorrido. */
.v-pasos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 30px; }
.v-paso {
  position: relative; padding: 20px 16px 18px; border-radius: 14px;
  background: var(--v-bg); border: 1px solid var(--v-border); text-align: center;
}
.v-paso-num {
  position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
  width: 24px; height: 24px; border-radius: 50%; background: var(--v-deep); color: #fff;
  font-family: 'Archivo', sans-serif; font-size: 12px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.v-paso-emoji   { display: block; font-size: 30px; margin: 6px 0 10px; }
.v-paso-titulo  { display: block; font-size: 15px; color: var(--v-ink); margin-bottom: 5px; }
.v-paso-detalle { display: block; font-size: 12.5px; color: var(--v-ink-2); line-height: 1.45; }

.v-rubrica-head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.v-rubrica { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 30px; }
.v-rubrica-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border-radius: 11px; border: 1px solid var(--v-border); background: #fff;
}
.v-rubrica-emoji { font-size: 21px; flex: 0 0 auto; }
.v-rubrica-fase  { font-size: 13.5px; font-weight: 700; color: var(--v-ink); }
.v-rubrica-que   { font-size: 12px; color: var(--v-ink-2); line-height: 1.35; }

.v-practica-cta {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding-top: 24px; border-top: 1px solid var(--v-border);
}

@media (max-width: 680px) {
  .v-practica { padding: 24px 18px; }
  .v-practica-head { gap: 14px; margin-bottom: 26px; }
  .v-practica-icon { width: 56px; height: 56px; font-size: 28px; border-radius: 16px; }
  /* Los pasos apilados mantienen el número: es lo que los ordena. */
  .v-pasos { grid-template-columns: 1fr; gap: 16px; }
  .v-paso { display: flex; align-items: center; gap: 14px; text-align: left; padding: 14px 16px; }
  .v-paso-num { position: static; transform: none; flex: 0 0 auto; }
  .v-paso-emoji { margin: 0; font-size: 26px; }
  .v-paso-texto { flex: 1; min-width: 0; }
  .v-rubrica { grid-template-columns: 1fr; }
  .v-practica-cta { flex-direction: column; align-items: stretch; text-align: center; }
}

/* ── Reproductor de cápsulas ─────────────────────────────────────────────── */
/*
 * La cápsula está construida a 16/9 por dentro: es la proporción que usa su
 * propio maquetado. Si el iframe tiene otra, la cápsula centra su contenido y
 * deja franjas blancas a los lados —que es exactamente lo que se veía.
 *
 * La caja mantiene 16/9 SIEMPRE. El `max-width` se deriva del alto disponible,
 * así que cuando la altura es el límite el ancho se reduce en proporción en
 * lugar de estirarse y volver a generar franjas.
 */
.v-capsula {
  position: relative; width: 100%;
  aspect-ratio: 16 / 9;
  max-width: calc((100vh - var(--capsula-chrome)) * 16 / 9);
  margin: 0 auto;
  border-radius: 14px; overflow: hidden;
  border: 1px solid var(--v-border); background: var(--v-deep);
  --capsula-chrome: 200px;   /* cabecera + barra de lecciones + navegación */
}
.v-capsula iframe { width: 100%; height: 100%; border: none; display: block; background: #fff; }

/* En pantalla completa manda la pantalla, no el cálculo. */
.v-capsula:fullscreen {
  max-width: none; width: 100vw; height: 100vh;
  aspect-ratio: auto; border: none; border-radius: 0;
  display: flex; align-items: center; justify-content: center;
}
.v-capsula:fullscreen iframe { aspect-ratio: 16 / 9; width: auto; height: 100%; max-width: 100vw; }

.v-capsula-full {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  background: rgba(12, 59, 54, .72); color: #fff; border: none;
  border-radius: 9px; padding: 9px 11px; cursor: pointer; line-height: 0;
}
.v-capsula-full:hover { background: rgba(12, 59, 54, .92); }

@media (max-width: 960px) { .v-capsula { --capsula-chrome: 168px; } }
@media (max-width: 680px) {
  /* En un teléfono vertical, 16/9 deja la cápsula muy chica. Se le da el ancho
     completo del contenido y se empuja la pantalla completa, que es donde
     realmente se puede trabajar. */
  .v-capsula { --capsula-chrome: 150px; max-width: 100%; border-radius: 12px; }
}

/* ── Atajos del resumen de la malla ──────────────────────────────────────── */
/* Sin señal de que se puede tocar, un elemento clicable es un elemento que
   nadie toca. De ahí el desplazamiento y la flecha al pasar por encima. */
/* Las cinco fases reparten el ancho en partes iguales: si una se ensancha
   porque su etiqueta es más larga («En curso» contra «✓»), la fila deja de
   leerse como un recorrido de cinco pasos iguales. */
.v-phase-chip { display: block; flex: 1; text-align: center; transition: transform .15s; }
.v-phase-chip:hover { transform: translateY(-3px); }
.v-phase-chip.is-locked { opacity: .75; }
.v-phase-chip.is-locked:hover { transform: none; }

.v-line-row {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 10px; margin: 0 -10px; border-radius: 10px;
  transition: background .15s;
}
.v-line-row:hover { background: var(--v-bg); }
.v-line-row.is-locked { opacity: .68; }
/* La flecha hereda su color de acá y no del atributo `stroke` del SVG: es lo
   que permite que el mismo icono viva en modo claro y oscuro sin tocarlo. */
.v-line-arrow { flex: 0 0 auto; opacity: 0; color: var(--v-muted-2); transition: opacity .15s, transform .15s; }
.v-line-row:hover .v-line-arrow { opacity: 1; transform: translateX(2px); }

/* ── Tabla ───────────────────────────────────────────────────────────────── */
.v-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.v-table th {
  text-align: left; font-family: 'Archivo', sans-serif; font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--v-muted);
  font-weight: 700; padding: 12px 14px; border-bottom: 1px solid var(--v-border);
}
.v-table td { padding: 14px; border-bottom: 1px solid var(--v-fill-2); }
.v-table tr:last-child td { border-bottom: none; }

/* ── Formularios ─────────────────────────────────────────────────────────── */
/* `.v-field` y `.v-input` estaban declarados DOS veces —acá y en el bloque de
   cuenta—, así que esta copia le pisaba el `display:flex` a la otra y el
   formulario de perfil perdía su `gap`. Una sola definición, arriba. */
.v-label { display: block; font-size: 13px; font-weight: 700; color: var(--v-ink); margin-bottom: 7px; }
.v-error { color: var(--v-danger-fg); font-size: 13px; margin-top: 6px; }

.v-alert { border-radius: var(--v-radius-sm); padding: 13px 16px; font-size: 14px; margin-bottom: 18px; }
.v-alert-error { background: var(--v-danger-bg); color: var(--v-danger-fg); border: 1px solid var(--v-danger-border); }
.v-alert-info  { background: var(--v-info-bg);   color: var(--v-info-fg); }
.v-alert-ok    { background: var(--v-ok-bg);     color: var(--v-ok-fg); }

/* ── Estado vacío ────────────────────────────────────────────────────────── */
.v-empty {
  text-align: center; padding: 56px 24px; color: var(--v-muted);
  background: var(--v-surface); border: 1px dashed var(--v-border); border-radius: var(--v-radius);
}
/* Un estado vacío tiene siempre las mismas tres piezas: un icono grande que
   avisa desde lejos que no hay nada, una frase que explica qué pasó y una que
   dice qué hacer. Estaban escritas a mano —y con tamaños distintos— en cada
   vista que podía quedarse sin datos. */
.v-empty-icon  { display: block; font-size: 38px; margin-bottom: var(--v-sp-3); }
.v-empty-title { display: block; color: var(--v-ink); margin-bottom: var(--v-sp-1); }
/* La salida —«ir a mi malla»— necesita despegarse de la frase, o se lee como
   parte del párrafo y deja de parecer un botón. */
.v-empty-cta   { margin-top: var(--v-sp-4); }
/* En una columna angosta —el panel de retos— 56 px de relleno dejan el cartel
   de vacío más alto que las tarjetas que lo rodean, y el vacío pesa más que el
   contenido. */
.v-empty-sm    { padding: var(--v-sp-5) var(--v-sp-4); }

/* ── Cajón de VITY ───────────────────────────────────────────────────────── */
.v-drawer-backdrop { position: fixed; inset: 0; z-index: 60; }
.v-drawer-scrim { position: absolute; inset: 0; background: rgba(16, 26, 36, .45); }
.v-drawer {
  position: absolute; top: 0; right: 0; height: 100%; width: 440px; max-width: 100%;
  background: #fff; display: flex; flex-direction: column;
  box-shadow: -16px 0 50px rgba(0, 0, 0, .22); animation: erDrawer .28s cubic-bezier(.2, .8, .2, 1);
}
.v-msg-user {
  align-self: flex-end; max-width: 80%; background: var(--v-green); color: #fff;
  padding: 13px 16px; border-radius: 14px 14px 4px 14px; font-size: 14px; line-height: 1.5;
}
.v-msg-bot {
  /* `var(--v-surface)` y no `#fff`: la burbuja vive dentro del cajón de Vity,
     cuyo fondo sigue el tema. Con el blanco fijo, en modo oscuro quedaba una
     tarjeta blanca con texto claro encima. */
  align-self: flex-start; max-width: 88%; background: var(--v-surface); border: 1px solid var(--v-border);
  padding: 15px 17px; border-radius: 14px 14px 14px 4px; font-size: 14px; line-height: 1.6; color: var(--v-ink);
}
.v-source {
  display: flex; align-items: center; gap: 8px; background: var(--v-bg);
  border-radius: 9px; padding: 9px 12px; font-size: 12px; color: var(--v-ink-2); margin-top: 10px;
}
.v-chip {
  font-size: 12px; font-weight: 600; color: var(--v-ink-2); background: var(--v-bg);
  border: 1px solid var(--v-border); border-radius: 99px; padding: 6px 12px; cursor: pointer;
}
.v-chip:hover { border-color: var(--v-green); color: var(--v-green); }
/* ═══════════════════════════════════════════════════════════════════════════
   COMPONENTES

   Todo lo que antes vivía en 544 atributos `style` repartidos por las vistas.
   La regla es simple y no tiene excepciones: **una vista no escribe colores,
   tamaños ni espaciados**. Sólo elige clases.

   Lo único que sigue viajando inline son los valores que dependen del dato
   —la imagen de portada y el porcentaje de una barra—, y viajan como
   *custom properties* (`--img`, `--pct`), no como declaraciones sueltas.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Utilidades de composición ───────────────────────────────────────────── */
/* Cuatro primitivas, no cuarenta. Alcanzan para el 90 % de los casos. */
.v-row        { display: flex; align-items: center; gap: var(--v-sp-3); }
.v-row-start  { align-items: flex-start; }
.v-row-end    { align-items: flex-end; }
.v-row-wrap   { flex-wrap: wrap; }
.v-between    { justify-content: space-between; }
.v-stack      { display: flex; flex-direction: column; gap: var(--v-sp-3); }
.v-stack-sm   { gap: var(--v-sp-2); }
.v-stack-lg   { gap: var(--v-sp-5); }
.v-push       { margin-left: auto; }
.v-fill-rest  { flex: 1; min-width: 0; }
.v-fixed      { flex: 0 0 auto; }
.v-nowrap     { white-space: nowrap; }
.v-truncate   { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v-mt-auto    { margin-top: auto; }

/*
 * La escala va COMPLETA del 1 al 6, aunque hoy no se usen todos.
 *
 * Una utilidad que falta no da error: simplemente no hace nada, y el hueco
 * aparece semanas después en una pantalla que nadie relaciona con esto. Así
 * quedó el logotipo pegado al rótulo «Hub Comercial» —el markup pedía
 * `v-mt-3`, que no existía— y así quedó una fila del detalle de persona sin
 * estilo por pedir una clase con un sufijo de más.
 */
/* Grilla que NO estira: cada tarjeta toma su altura natural.
   Por defecto las columnas se igualan, y una tarjeta con poco contenido al lado
   de otra larga queda con un hueco vacío abajo que parece un error de carga. */
.v-grid-top { align-items: start; }

.v-gap-1 { gap: var(--v-sp-1); } .v-gap-2 { gap: var(--v-sp-2); }
.v-gap-3 { gap: var(--v-sp-3); } .v-gap-4 { gap: var(--v-sp-4); }
.v-gap-5 { gap: var(--v-sp-5); } .v-gap-6 { gap: var(--v-sp-6); }
.v-mb-1  { margin-bottom: var(--v-sp-1); }
.v-mb-4  { margin-bottom: var(--v-sp-4); }
.v-mb-5  { margin-bottom: var(--v-sp-5); }
.v-mb-6  { margin-bottom: var(--v-sp-6); }

/* ── Texto ───────────────────────────────────────────────────────────────── */
.v-text     { font-size: 14px; color: var(--v-ink-2); line-height: 1.55; }
.v-text-sm  { font-size: 13px; color: var(--v-ink-2); line-height: 1.5; }
.v-meta     { font-size: 12px; color: var(--v-muted); }
.v-meta-sm  { font-size: 11px; color: var(--v-muted); }
/* 12 px pero con el color del texto, no el del apagado: hay metadatos que son
   contenido —quién es el responsable de un documento— y no ruido de interfaz. */
.v-text-xs  { font-size: 12px; color: var(--v-ink-2); line-height: 1.45; }
.v-ink      { color: var(--v-ink); }
.v-accent   { color: var(--v-green); }
.v-title    { font-size: 16px; font-weight: 700; line-height: 1.35; color: var(--v-ink); margin: 0; }
.v-title-lg { font-size: 18px; font-weight: 800; line-height: 1.3; color: var(--v-ink); margin: 0; }
.v-eyebrow  {
  font-family: 'Archivo', sans-serif; font-size: 10px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--v-muted);
}

/* ── Cabecera de página ──────────────────────────────────────────────────── */
.v-page-head { margin-bottom: var(--v-sp-5); }
/* Título con una acción chica al lado —«Conectar con mi calendario»—. Se separa
   de `.v-page-head-split` porque ahí la acción se va al extremo opuesto de la
   fila; acá tiene que quedar PEGADA al título, para que se lea como algo que
   se le hace a esa página y no como una acción global de la pantalla.
   El `baseline` alinea el texto del botón con el del titular en vez de centrar
   dos cajas de alturas muy distintas; al envolver, el botón baja completo. */
.v-title-row { align-items: baseline; margin-bottom: var(--v-sp-2); }
.v-page-head-split {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--v-sp-5); flex-wrap: wrap; margin-bottom: 28px;
}

/* ── Imagen y progreso gobernados por el dato ────────────────────────────── */
/* Uso: style="--img:url('…')" — una sola propiedad, no cinco declaraciones. */
.v-img {
  background-image: var(--img); background-size: cover; background-position: center;
  background-color: var(--v-fill); background-repeat: no-repeat;
}
/* Uso: <span style="--pct:62%"> dentro de .v-bar */
.v-bar > span { width: var(--pct, 0%); }

/* ── Píldora de estado ───────────────────────────────────────────────────── */
.v-pill {
  display: inline-flex; align-items: center; gap: var(--v-sp-2);
  border-radius: 999px; padding: 10px 18px; font-size: 13px; font-weight: 700;
  background: var(--v-ok-bg); color: var(--v-ok-fg);
}
.v-pill-dot { width: 9px; height: 9px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }

/* ── Iniciales ───────────────────────────────────────────────────────────── */
.v-initials {
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: 50%;
  background: var(--v-green); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800;
}
.v-initials-sm { width: 26px; height: 26px; font-size: 10px; background: var(--v-fill); color: var(--v-ink-2); }

/* ── Iconografía ─────────────────────────────────────────────────────────── */
/* Los SVG del sistema comparten trazo y tamaño; los emoji quedan como acento
   emocional (títulos, estados vacíos), nunca como control. */
.v-icon { width: 20px; height: 20px; flex: 0 0 auto; display: block; }
/* Los SVG del sistema pintan con `currentColor`, así que el color se elige
   acá y no en un atributo `stroke` con un hex adentro. */
.v-muted-icon { color: var(--v-muted); }
.v-accent-icon { color: var(--v-green); }
.v-on-dark-icon { color: #fff; }
.v-icon-sm { width: 16px; height: 16px; }
.v-icon-lg { width: 26px; height: 26px; }
.v-emoji { font-style: normal; line-height: 1; }
.v-emoji-lg { font-size: 30px; }
.v-emoji-xl { font-size: 38px; }

/* ── Inicio: continuar donde quedaste ────────────────────────────────────── */
.v-continue { padding: 28px 30px; }
.v-continue-body { display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }
.v-continue-letter {
  width: 120px; height: 120px; flex: 0 0 auto; border-radius: 12px;
  background: var(--v-deep); color: var(--v-on-deep);
  display: flex; align-items: center; justify-content: center;
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 64px;
}
.v-continue-main { flex: 1; min-width: 220px; }
.v-continue-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 24px;
  text-transform: uppercase; margin: 4px 0 10px;
}

/* ── Inicio: tarjeta de Vity ─────────────────────────────────────────────── */
.v-vity-card { display: flex; flex-direction: column; }
.v-vity-name { font-weight: 800; font-size: 16px; }
.v-vity-role { font-size: 11px; color: var(--v-muted); }
.v-vity-copy { font-size: 14px; line-height: 1.55; color: var(--v-on-deep-soft); margin: 0 0 var(--v-sp-4); }

/* ── Inicio: próxima reunión ─────────────────────────────────────────────── */
.v-next-live {
  display: flex; align-items: center; gap: var(--v-sp-3);
  background: var(--v-surface); border: 1px solid var(--v-border);
  border-radius: var(--v-radius); padding: 18px 24px; margin-bottom: 26px;
  transition: border-color .15s;
}
.v-next-live:hover { border-color: var(--v-green); }
.v-next-live-cta {
  background: var(--v-green); color: #fff; border-radius: var(--v-radius-sm);
  padding: 9px 16px; font-size: 13px; font-weight: 700; white-space: nowrap;
}

/* ── Inicio: atajo de fase ───────────────────────────────────────────────── */
.v-phase-tile {
  height: 52px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 26px;
  background: var(--v-fill); color: var(--v-ink-2);
}
.v-phase-tile.is-certified { background: var(--v-ok-bg);     color: var(--v-ok-fg); }
.v-phase-tile.is-progress  { background: var(--v-warn-solid); color: #fff; }
.v-phase-tile.is-locked    { background: var(--v-fill);      color: var(--v-muted-2); }
.v-phase-note { font-size: 10px; margin-top: 5px; font-weight: 700; color: var(--v-muted-2); }
.v-phase-note.is-certified { color: var(--v-ok-fg); }
.v-phase-note.is-progress  { color: var(--v-warn-fg); }

/* ── Bloque de portada con velo ──────────────────────────────────────────── */
/* Lo comparten la inducción de la malla y la cabecera de reuniones. */
.v-hero {
  position: relative; overflow: hidden; border-radius: var(--v-radius);
  background: var(--v-deep); color: var(--v-on-deep);
}
.v-hero-media { position: absolute; inset: 0; opacity: .30; }
/* El encuadre de la fachada: el cartel de la tienda vive por encima del centro
   de la foto y un centrado exacto lo deja fuera del recorte. */
.v-hero-media-store { background-position: center 62%; }
.v-hero-veil {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--v-deep) 12%, rgba(12, 59, 54, .86) 45%, rgba(12, 59, 54, .78) 100%);
}
.v-hero-body {
  position: relative; padding: 24px 28px;
  display: flex; align-items: center; gap: 30px; flex-wrap: wrap;
}
.v-hero-intro { flex: 0 0 auto; max-width: 250px; }
.v-hero-eyebrow {
  font-family: 'Archivo', sans-serif; font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--v-muted-2); font-weight: 700; margin-bottom: 4px;
}
.v-hero-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 23px;
  text-transform: uppercase; margin: 0;
}
.v-hero-state {
  display: inline-flex; align-items: center; gap: var(--v-sp-1); margin-top: 12px;
  background: var(--v-green); color: #fff; border-radius: 99px;
  padding: 5px 13px; font-size: 12px; font-weight: 700;
}
.v-hero-state.is-done { background: var(--v-green-2); }
/* Hermano de `.v-hero-cards` para los héroes que llevan un párrafo en vez de
   tres fichas: la pantalla de inducción muestra el resumen del curso tal como
   lo escribió el curador. Mismo `flex: 1` y mismo `min-width`, o el texto se
   apretaría contra el intro en vez de bajar. El color es `--v-on-deep-soft`
   —7,80:1 sobre el velo en claro, 10,80:1 en oscuro—, no un gris cualquiera. */
.v-hero-summary {
  position: relative; flex: 1; min-width: 280px; margin: 0;
  color: var(--v-on-deep-soft); font-size: 15px; line-height: 1.55;
}
.v-hero-cards {
  position: relative; flex: 1; min-width: 280px; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--v-sp-3);
}
.v-hero-card { background: rgba(20, 82, 74, .92); border-radius: 11px; padding: 16px 18px; }
.v-hero-card-title { font-size: 14px; font-weight: 700; margin-bottom: 4px; }
.v-hero-card-note  { font-size: 12px; color: var(--v-muted); line-height: 1.45; }

/* Variante de banda: sin tarjetas, sólo un titular sobre la foto. */
.v-hero-band { height: clamp(130px, 26vw, 190px); margin-bottom: var(--v-sp-4); }
.v-hero-band .v-hero-media { opacity: 1; }
.v-hero-band .v-hero-veil {
  background: linear-gradient(90deg, rgba(12, 59, 54, .86) 0%, rgba(12, 59, 54, .35) 60%, rgba(12, 59, 54, 0) 100%);
}
/* La foto del equipo se encuadra un poco por encima del centro. Centrada, la
   banda corta las caras justo a la altura de los ojos y la portada deja de
   mostrar personas para mostrar frentes. */
.v-hero-band .v-hero-media { background-position: center 40%; }
.v-hero-band-body { position: absolute; left: 28px; bottom: 24px; max-width: 420px; }
.v-hero-band-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 22px;
  text-transform: uppercase; margin-top: 6px;
}

/* ── Malla: tarjeta de línea de producto ─────────────────────────────────── */
.v-line-card { padding: 0; overflow: hidden; }
.v-line-cover { position: relative; height: 118px; }
.v-line-cover .v-badge { position: absolute; top: 10px; left: 10px; }
.v-line-body { padding: 16px 18px; }
.v-line-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 17px;
  text-transform: uppercase; margin: 0 0 3px; line-height: 1.15;
}
.v-line-cta { font-size: 12px; font-weight: 700; margin-top: var(--v-sp-2); color: var(--v-green); }
.v-line-cta.is-locked { color: var(--v-muted); }
.v-line-thumb { width: 34px; height: 34px; border-radius: 8px; flex: 0 0 auto; }

/* ── Banco: filtros y tarjetas de documento ──────────────────────────────── */
.v-filters { display: flex; gap: var(--v-sp-2); flex-wrap: wrap; margin-bottom: 22px; }
.v-filter { border-radius: 99px; border: 1px solid var(--v-border); }

/* ── Banco: buscador de la pantalla ──────────────────────────────────────── */
/* El del encabezado global en celular vive plegado detrás de un botón. Este
   está desplegado y arriba de todo, que es lo que se pidió. */
.v-banco-buscador {
  display: flex; align-items: center; gap: var(--v-sp-2);
  background: var(--v-surface); border: 1px solid var(--v-border);
  border-radius: 14px; padding: 8px 10px 8px 14px; margin-bottom: 18px;
}
.v-banco-buscador:focus-within { border-color: var(--v-green); }
.v-banco-buscador-campo {
  flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font: inherit; color: var(--v-ink); padding: 6px 0;
}
/* El aspa que Safari y Chrome ponen dentro de `type="search"` hereda un color
   propio que en tema oscuro queda invisible. */
.v-banco-buscador-campo::-webkit-search-cancel-button { filter: grayscale(1) opacity(.6); }

/* ── Banco: cajas o lista ────────────────────────────────────────────────── */
.v-vista-toggle {
  display: flex; gap: 2px; padding: 3px;
  background: var(--v-fill); border: 1px solid var(--v-border); border-radius: 12px;
}
.v-vista-btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; background: none; cursor: pointer;
  font-family: 'Archivo', sans-serif; font-size: 12px; font-weight: 700;
  color: var(--v-ink-2); padding: 7px 12px; border-radius: 9px;
  transition: background .15s, color .15s;
}
.v-vista-btn:hover { color: var(--v-ink); }
.v-vista-btn.is-on { background: var(--v-surface); color: var(--v-ink); box-shadow: var(--v-shadow-sm); }

/* Un solo contenedor para las dos vistas: cambia la clase, no el marcado. */
.v-doc-lista { display: grid; gap: 18px; }
.v-doc-lista.is-cajas { grid-template-columns: repeat(3, 1fr); }
.v-doc-lista.is-lista { grid-template-columns: 1fr; gap: 10px; }

.v-doc-card { display: flex; flex-direction: column; overflow: hidden; }
.v-doc-card.is-expired { opacity: .82; }
/* Portada a sangre: los márgenes negativos compensan el padding de la tarjeta. */
.v-doc-cover { height: 104px; margin: -24px -26px 18px; }
/* La foto real: el encuadre lo manda la vista con `--encuadre`, distinto por
   documento. El respaldo `center` es el de `.v-img`, que sigue valiendo si
   algún día alguien pone la clase sin la variable. */
.v-doc-cover-foto { background-position: var(--encuadre, center); }

/* La tarjeta en fila: la portada a la izquierda y el texto en una columna.
   Todo lo que no es la portada se fuerza a la columna 2 en vez de dejarlo al
   acomodo automático: con la portada ocupando tres filas, el cuarto hijo —el
   sello de vencido, que sólo aparece a veces— caería en la columna 1 y la
   tarjeta se desarmaría justo en los documentos vencidos. */
.v-doc-lista.is-lista .v-doc-card {
  display: grid; grid-template-columns: 96px minmax(0, 1fr);
  align-items: center; column-gap: 16px; row-gap: 2px; padding: 12px 16px;
}
.v-doc-lista.is-lista .v-doc-card > *:not(.v-doc-cover) { grid-column: 2; }
.v-doc-lista.is-lista .v-doc-cover {
  grid-column: 1; grid-row: 1 / span 3;
  height: 62px; margin: 0; border-radius: 10px;
}
.v-doc-lista.is-lista .v-doc-cover-emoji { font-size: 26px; }
/* El resumen se va: es lo que ocupa el alto que la lista viene a recuperar.
   El título y el responsable alcanzan para elegir, y el resumen entero está a
   un clic en la ficha. */
.v-doc-lista.is-lista .v-doc-summary { display: none; }
.v-doc-lista.is-lista .v-doc-card .v-row { margin-bottom: 0; }
.v-doc-lista.is-lista .v-title { margin-bottom: 2px; }
.v-doc-lista.is-lista .v-doc-foot { margin-top: 4px; border-top: 0; padding-top: 0; }

/*
 * ── Portada generada ────────────────────────────────────────────────────────
 *
 * `kb_documents` no tiene columna de portada: la única imagen del banco es la
 * de la CATEGORÍA, y repartirla por categoría era lo que hacía que los doce
 * documentos de «Organización» se vieran iguales. Hasta que exista una portada
 * por documento —decisión de producto, con su campo de carga—, la tarjeta se
 * pinta sola con lo que sí se sabe: el tipo manda el color y el ícono, y el
 * slug manda el ángulo del degradado y dónde cae el brillo.
 *
 * Los dos valores llegan como variables desde la vista y salen de `crc32` del
 * slug, así que el mismo documento se ve siempre igual. Ver `portada_helper`:
 * si esto fuera aleatorio, la tarjeta cambiaría de color en cada recarga y se
 * perdería la referencia visual con la que la gente encuentra un documento sin
 * leer el título.
 *
 * El respaldo de `--v-doc-tipo` es el verde de marca: un tipo que todavía no
 * tenga clase se ve entero, no a medio pintar.
 */
.v-doc-cover-gen {
  --v-doc-tipo: var(--v-green);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  background:
    radial-gradient(circle at var(--mancha, 50%) 28%, rgba(255, 255, 255, .18), transparent 62%),
    linear-gradient(var(--angulo, 135deg), var(--v-doc-tipo), var(--v-deep));
}
.v-doc-cover-gen.is-pdf      { --v-doc-tipo: var(--v-type-pdf); }
.v-doc-cover-gen.is-video    { --v-doc-tipo: var(--v-type-video); }
.v-doc-cover-gen.is-onepager { --v-doc-tipo: var(--v-type-onepager); }
.v-doc-cover-gen.is-vr360    { --v-doc-tipo: var(--v-type-vr360); }
.v-doc-cover-gen.is-tool     { --v-doc-tipo: var(--v-type-tool); }
.v-doc-cover-gen.is-link     { --v-doc-tipo: var(--v-type-link); }
/* El ícono es decorativo y va con `aria-hidden`: el tipo ya está escrito en
   `.v-doc-type`, y leerlo dos veces sólo alarga el recorrido del lector. */
.v-doc-cover-emoji {
  font-size: 38px; line-height: 1;
  /* La sombra lo despega del degradado en los tipos claros —`onepager` sobre
     azul— sin cambiarle el color al emoji, que trae el suyo propio. */
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .35));
}

.v-doc-type {
  font-family: 'Archivo', sans-serif; font-size: 10px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: #fff;
  padding: 4px 9px; border-radius: 7px; background: var(--v-type-link);
}
.v-doc-type.is-pdf      { background: var(--v-type-pdf); }
.v-doc-type.is-video    { background: var(--v-type-video); }
.v-doc-type.is-onepager { background: var(--v-type-onepager); }
.v-doc-type.is-vr360    { background: var(--v-type-vr360); }
.v-doc-type.is-tool     { background: var(--v-type-tool); }
.v-doc-summary { font-size: 13px; color: var(--v-ink-2); line-height: 1.5; margin: 0 0 auto; }
.v-doc-foot {
  display: flex; align-items: center; gap: 8px;
  margin-top: var(--v-sp-4); padding-top: var(--v-sp-3); border-top: 1px solid var(--v-fill-2);
}
.v-doc-valid { margin-left: auto; font-size: 11px; color: var(--v-muted); }
.v-doc-valid.is-expired { color: var(--v-danger-fg); }
/* El aviso de vencido va dentro de la tarjeta, no arriba: se lee junto al
   título, que es donde alguien decide si el documento le sirve o no. */
.v-doc-flag { margin-top: var(--v-sp-3); align-self: flex-start; }

/* ── Ficha de documento ──────────────────────────────────────────────────── */
/* Acá se lee texto largo, no se escanea una tarjeta: más aire a los costados
   que en una `.v-card` común, y una medida de línea que no canse. */
.v-doc-page { padding: 36px 40px; }
/* La cinta de metadatos —responsable, versión, vigencia, consultas— la
   comparten la ficha y el visor. La variante `is-ruled` es la de la ficha, que
   la usa como separador entre la cabecera y el cuerpo del documento. */
.v-doc-meta {
  display: flex; align-items: center; gap: var(--v-sp-4);
  flex-wrap: wrap; margin-top: var(--v-sp-2);
}
.v-doc-meta.is-ruled {
  margin: var(--v-sp-5) 0; padding-bottom: var(--v-sp-5);
  border-bottom: 1px solid var(--v-fill-2);
}
/* Una fecha vencida se dice con color Y con palabra («Venció el…»): el color
   solo no llega a quien no lo distingue. */
.v-doc-meta .is-expired { color: var(--v-danger-fg); }
.v-doc-lead { font-size: 17px; line-height: 1.65; color: var(--v-ink); margin: 0 0 var(--v-sp-5); }
/* `pre-line` porque el texto viene del buscador con sus saltos de línea
   propios: sin eso, un documento entero se aplana en un solo párrafo. */
.v-doc-body { font-size: 15px; line-height: 1.75; color: var(--v-ink-2); white-space: pre-line; }

/* ── Visor de PDF ────────────────────────────────────────────────────────── */
.v-visor {
  position: relative; overflow: hidden;
  border: 1px solid var(--v-border); border-radius: var(--v-radius);
  background: var(--v-visor-bg);
}
/*
 * OJO: esta altura es FUNCIONAL, no decorativa. Un iframe sin alto explícito
 * colapsa a 150 px y el PDF queda ilegible. `min(78vh, 900px)` le da casi toda
 * la pantalla sin estirarse de más en un monitor vertical, y el `min-height`
 * sostiene el caso del teléfono apaisado, donde 78vh son cuatro renglones.
 */
.v-visor iframe {
  display: block; width: 100%; border: none;
  height: min(78vh, 900px); min-height: 420px;
}
.v-visor-note {
  display: flex; align-items: center; gap: var(--v-sp-2);
  margin-top: var(--v-sp-3); font-size: 12px; color: var(--v-muted);
}

/* ── Llamado a Vity al pie de un material ────────────────────────────────── */
/* La misma pieza en la ficha y en el visor: quien terminó de leer y quedó con
   una duda tiene que encontrar dónde preguntarla sin volver al menú. */
.v-ask-vity {
  display: flex; align-items: center; gap: var(--v-sp-4);
  flex-wrap: wrap; margin-top: var(--v-sp-5);
}
.v-ask-vity .v-vity { width: 48px; height: 48px; }
.v-ask-vity-main  { flex: 1; min-width: 200px; }
.v-ask-vity-title { font-weight: 800; font-size: 15px; }
.v-ask-vity-note  { font-size: 13px; color: var(--v-on-deep-soft); }

/* ── Verificación pública de certificado ─────────────────────────────────── */
/*
 * Página suelta: no usa el armazón del Hub porque quien la abre viene de
 * escanear un QR en papel y no tiene sesión. Una sola tarjeta centrada sobre
 * el verde de marca, sin menú ni cabecera que la distraigan.
 */
.v-verify-shell {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: var(--v-sp-5); background: var(--v-deep);
}
.v-verify-card { width: 100%; max-width: 520px; padding: var(--v-sp-6); }
.v-verify-logo { text-align: center; margin-bottom: var(--v-sp-6); }
.v-verify-logo img { display: block; margin: 0 auto; }
.v-verify-result { text-align: center; }
.v-verify-result p { margin: 0; }
/* El estado es el `<h1>` de la página, pero se ve como insignia: hay que
   quitarle el margen que el navegador le da a cualquier encabezado. */
.v-verify-state { margin: 0; }
/* El emoji acompaña; el que informa es el texto de la insignia. Por eso va
   `aria-hidden` en la vista: leerlo en voz alta no agrega nada. */
.v-verify-icon { display: block; font-size: 44px; margin-bottom: var(--v-sp-3); }
/* `fixed` + ancho de la primera columna: sin eso un nombre largo del titular
   empuja las etiquetas y cada fila arranca en un lugar distinto. */
.v-verify-table { table-layout: fixed; margin-bottom: var(--v-sp-1); }
.v-verify-table th { width: 40%; }
.v-verify-holder { font-weight: 700; }
/* El código se compara carácter por carácter contra el del papel: monoespaciada
   y partible, porque no tiene espacios donde cortar. */
.v-verify-code { font-family: monospace; font-size: 12px; word-break: break-all; }
.v-verify-foot {
  text-align: center; margin: var(--v-sp-5) 0 0;
  padding-top: var(--v-sp-4); border-top: 1px solid var(--v-fill-2);
  font-size: 12px; color: var(--v-muted);
}

/* ── Certificados y reuniones: fila con icono ────────────────────────────── */
.v-item-row { display: flex; align-items: center; gap: var(--v-sp-4); }
.v-item-row.is-dim { opacity: .68; }
.v-item-icon {
  width: 60px; height: 60px; flex: 0 0 auto; border-radius: 13px;
  background: var(--v-mine-bg);
  display: flex; align-items: center; justify-content: center; font-size: 32px;
}
.v-item-icon-alt { background: var(--v-bg); width: 58px; height: 58px; font-size: 30px; }
/* El título de la fila pesa más que un `.v-title` común: en una lista de
   certificados es lo único que se lee de reojo. */
.v-item-title { font-size: 16px; font-weight: 800; line-height: 1.3; margin: 3px 0 4px; }
/* El estado de vigencia cuelga bajo la fecha. El `.v-badge` es inline y sin
   este respiro se pega al renglón anterior como si fuera parte de él. */
.v-item-state { margin-top: var(--v-sp-1); }

.v-live-row { padding: 22px 26px; flex-wrap: wrap; gap: 22px; }
.v-live-main { flex: 1; min-width: 220px; }
/* La reunión abre con el estado y el tipo de sesión: una línea de contexto
   antes del título, no un título suelto que hay que abrir para entender. */
.v-live-meta {
  display: flex; align-items: center; gap: var(--v-sp-2);
  flex-wrap: wrap; margin-bottom: var(--v-sp-1); font-weight: 600;
}
/* Título y fecha son un solo bloque: 4 px los separan sin desarmarlo. */
.v-live-main .v-title-lg { margin-bottom: 4px; }

/* ── Juego ───────────────────────────────────────────────────────────────── */
/* La grilla principal —insignias a la izquierda, retos y ranking al costado—
   es la misma `.v-grid-split` que usa el inicio: una sola proporción para
   «bloque que manda + bloque que acompaña», definida más abajo. */
.v-level { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; margin-bottom: 26px; }
/* El trofeo es el acento emocional de la tarjeta, no un icono de interfaz: por
   eso tiene su propio tamaño y no entra en la escala de `.v-icon`. */
.v-level-emoji { font-size: 56px; flex: 0 0 auto; }
/* Lo que falta para el próximo nivel va pegado a la barra: es su leyenda. */
.v-level-note { margin-top: 8px; }
.v-level-main { flex: 1; min-width: 260px; }
.v-level-name {
  font-family: 'Archivo', sans-serif; font-size: 12px; color: var(--v-muted);
  font-weight: 700; text-transform: uppercase; letter-spacing: .14em;
}
.v-level-pts {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 42px;
  line-height: 1; margin: 6px 0 12px; letter-spacing: -1px;
}
.v-level-pts small { font-size: 20px; color: var(--v-muted); letter-spacing: 0; }
.v-level-bar { height: 8px; background: var(--v-line-dark); border-radius: 99px; overflow: hidden; max-width: 520px; }
.v-level-bar > span { display: block; height: 100%; width: var(--pct, 0%); background: var(--v-green); }
.v-streak { text-align: center; padding: 0 var(--v-sp-3); }
.v-streak-days { font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 26px; }

/* La grilla de insignias va más apretada que las de contenido: son iconos de
   54 px, no tarjetas que haya que leer. El responsive ya usa esta clase para
   forzar dos columnas en celular. */
.v-badge-grid { gap: var(--v-sp-3); }

/* `position: relative` para que el «?» y su globo se cuelguen de la casilla.
   La opacidad de `.is-locked` NO puede alcanzar al botón de ayuda: la insignia
   pendiente es justo aquella sobre la que alguien se pregunta cómo se gana, y
   dejarla al 50 % haría ilegible la única respuesta. Ver `.v-ayuda` abajo. */
.v-badge-tile { text-align: center; padding: 18px 14px; position: relative; }
/* La insignia sin ilustración cae en el emoji de reserva. Necesita ocupar su
   propia línea, como la imagen a la que reemplaza. */
.v-badge-tile .v-emoji { display: block; margin-bottom: 8px; }
/*
 * La casilla pendiente se apaga por HIJOS y no como bloque.
 *
 * Antes era `.v-badge-tile.is-locked { opacity: .5 }`, y `opacity` en el padre
 * no se puede deshacer desde un hijo: crea un contexto de composición y arrastra
 * a TODO lo que tiene adentro, sin excepción posible. Con el «?» dentro de la
 * casilla, eso dejaba la explicación al 50 % justamente en las insignias que
 * todavía no se ganaron —que son las únicas sobre las que alguien se pregunta
 * cómo se ganan—.
 *
 * Apagando cada hijo menos el botón de ayuda, el efecto visual es el mismo y la
 * respuesta se lee entera.
 */
.v-badge-tile.is-locked > :not(.v-ayuda) { opacity: .5; }
.v-badge-tile.is-locked img, .v-badge-tile.is-locked .v-emoji { filter: grayscale(1); }
.v-badge-tile img { width: 54px; height: 54px; object-fit: contain; margin-bottom: var(--v-sp-2); }
.v-badge-tile-name { font-size: 12px; font-weight: 700; line-height: 1.3; }
.v-badge-tile-date { font-size: 10px; color: var(--v-ok-fg); font-weight: 700; margin-top: 5px; }

/* ── Globo de ayuda ──────────────────────────────────────────────────────────
 *
 * El «?» que explica cómo se gana cada insignia. Es un componente propio y no
 * una regla de `.v-badge-tile` porque la pregunta «¿esto cómo funciona?» se va
 * a repetir en otras cajas de la plataforma.
 *
 * Reemplaza al `title=""` que traía la casilla: ese atributo no se abre con
 * teclado, no existe en pantalla táctil —la mitad del piso de venta— y los
 * lectores de pantalla lo anuncian de forma inconsistente.
 */
.v-ayuda { position: absolute; top: 8px; right: 8px; }
.v-ayuda-btn {
  width: 22px; height: 22px; padding: 0; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--v-border); background: var(--v-surface);
  color: var(--v-ink-2); font-size: 12px; font-weight: 800; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.v-ayuda-btn:hover { border-color: var(--v-green); color: var(--v-green); }
/* Aro de foco explícito: es un botón chico y redondo, y el contorno que pone
   el navegador por defecto se pierde contra el borde de la casilla. Sin esto,
   quien navega con teclado no sabe dónde está parado. */
.v-ayuda-btn:focus-visible {
  outline: 2px solid var(--v-green); outline-offset: 2px;
}
.v-ayuda-globo {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 30;
  width: 232px; text-align: left;
  background: var(--v-surface); border: 1px solid var(--v-border);
  border-radius: var(--v-radius-sm); box-shadow: var(--v-shadow-md);
  padding: 12px 14px; font-size: 12px; line-height: 1.5; color: var(--v-ink-2);
  font-weight: 500;
}
.v-ayuda-globo-titulo {
  font-weight: 800; color: var(--v-ink); margin-bottom: 4px; font-size: 12px;
}
/* Cerca del borde derecho de la pantalla el globo de 232 px se sale. En
   angosto se ancla al lado opuesto y se deja crecer hasta donde haya lugar. */
@media (max-width: 680px) {
  .v-ayuda-globo { right: auto; left: 0; width: min(232px, 74vw); }
}

.v-challenge { padding: 16px 18px; }
/* Emoji, título y contador en una línea, y la barra debajo: el reto se lee de
   un vistazo sin que el contador se despegue de lo que cuenta. */
.v-challenge-head { display: flex; align-items: center; gap: var(--v-sp-2); margin-bottom: var(--v-sp-2); }
.v-challenge-emoji { font-size: 22px; flex: 0 0 auto; }
.v-challenge-title { flex: 1; min-width: 0; font-size: 14px; font-weight: 700; }
.v-challenge-count { font-size: 12px; color: var(--v-green); font-weight: 700; }
.v-challenge-done { font-size: 11px; color: var(--v-ok-fg); font-weight: 700; margin-top: 8px; }

.v-rank-row {
  border-radius: 12px; padding: 14px 18px; display: flex; align-items: center; gap: var(--v-sp-3);
  background: var(--v-surface); border: 1px solid var(--v-border);
}
.v-rank-row.is-me { background: var(--v-ok-bg); border-color: var(--v-green); }
.v-rank-pos {
  font-size: 15px; font-weight: 800; color: var(--v-muted);
  min-width: 28px; text-align: center; flex: 0 0 auto;
}
.v-rank-pos.is-medal { font-size: 24px; }
/* El nombre no es un título de tarjeta: en una lista de diez filas, 16 px
   convierten el ranking en una pared. */
.v-rank-name { font-size: 14px; font-weight: 700; }
.v-rank-pts { font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 20px; color: var(--v-green); }

/* ── Lección: barra de navegación e índice ───────────────────────────────── */
.v-lesson-bar {
  display: flex; align-items: center; gap: var(--v-sp-3);
  margin-bottom: var(--v-sp-4); flex-wrap: wrap;
}
.v-lesson-back {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 700; color: var(--v-muted); white-space: nowrap;
}
.v-lesson-back:hover { color: var(--v-green); }
.v-lesson-tabs {
  display: flex; align-items: center; gap: 8px;
  flex: 1; min-width: 0; overflow-x: auto; padding-bottom: 2px;
}
.v-lesson-tab {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  padding: 8px 14px; border-radius: 99px; font-size: 13px; font-weight: 600;
  white-space: nowrap; background: var(--v-surface); color: var(--v-ink-2);
  border: 1px solid var(--v-border);
}
.v-lesson-tab.is-current {
  background: var(--v-deep); color: var(--v-on-deep);
  border-color: var(--v-deep); font-weight: 700;
}
.v-lesson-num {
  width: 20px; height: 20px; flex: 0 0 auto; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; background: var(--v-fill); color: var(--v-muted-2);
}
.v-lesson-tab.is-current .v-lesson-num { background: var(--v-green); color: #fff; }
.v-lesson-num.is-done { background: var(--v-green-2); color: #fff; }
/* «Completada» le gana a «acá estás parado»: si no, la lección actual ya vista
   pierde su verde de certificada y parece pendiente. Hace falta la
   especificidad extra para vencer a la regla de `.is-current` de arriba. */
.v-lesson-tab.is-current .v-lesson-num.is-done { background: var(--v-green-2); }
.v-lesson-shell { max-width: 1500px; margin: 0 auto; animation: erFade .3s ease; }

/* ── Cajón de VITY: estructura ───────────────────────────────────────────── */
.v-drawer-head {
  background: var(--v-deep); color: var(--v-on-deep);
  padding: 22px 24px; display: flex; align-items: center; gap: var(--v-sp-3);
}
.v-drawer-body {
  flex: 1; overflow-y: auto; padding: 24px; background: var(--v-bg);
  display: flex; flex-direction: column; gap: var(--v-sp-4);
}
.v-drawer-foot { padding: 16px 20px; border-top: 1px solid var(--v-border); background: var(--v-surface); }
.v-drawer-form {
  display: flex; align-items: center; gap: var(--v-sp-2);
  background: var(--v-bg); border: 1px solid var(--v-border);
  border-radius: 12px; padding: 12px 15px;
}
.v-drawer-input { flex: 1; border: none; background: none; outline: none; font-size: 14px; color: var(--v-ink); }
.v-drawer-send {
  width: 38px; height: 38px; flex: 0 0 auto; border-radius: 9px; background: var(--v-green);
  border: none; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.v-drawer-chips { display: flex; gap: 8px; margin-bottom: var(--v-sp-3); flex-wrap: wrap; }
.v-drawer-close {
  background: none; border: none; cursor: pointer; padding: 4px;
  color: var(--v-muted); flex: 0 0 auto; line-height: 0;
}
.v-drawer-close:hover { color: #fff; }
/* Los atajos son botones: hacen algo, no llevan a ningún lado. */
.v-chip { font-family: inherit; }
.v-msg-pending { color: var(--v-muted); }
.v-msg-error   { margin: 0; color: var(--v-danger-fg); }

/* ── Búsqueda del encabezado ─────────────────────────────────────────────── */
.v-search {
  flex: 1; max-width: 440px; margin-left: var(--v-sp-3);
  display: flex; align-items: center; gap: var(--v-sp-2);
  background: var(--v-bg); border: 1px solid var(--v-border);
  border-radius: var(--v-radius-sm); padding: 10px 14px;
}
.v-search input { flex: 1; border: none; background: none; outline: none; font-size: 14px; color: var(--v-ink); }
/*
 * El marcador de posición NO tenía regla: quedaba en el gris que inventa cada
 * navegador (≈54 % del color del texto), que sobre `--v-bg` en claro da 2,9:1
 * —por debajo del mínimo— y en oscuro depende de si el navegador respetó
 * `color-scheme`. Con `--v-ink-2` da 5,19:1 en claro y 9,23:1 en oscuro, y es
 * el mismo gris de texto secundario del resto del sistema.
 *
 * `--v-muted` era el candidato natural por nombre, pero mide 3,02:1 sobre
 * `--v-bg`: alcanza para un icono (no-texto, 3:1) y no para una frase.
 */
.v-search input::placeholder { color: var(--v-ink-2); opacity: 1; }
.v-search:focus-within { border-color: var(--v-green); box-shadow: 0 0 0 3px var(--v-ring); }

/* Botón que abre la búsqueda en pantallas donde la barra no entra. */
.v-search-toggle { display: none; }

/* ── Cambio de tema ──────────────────────────────────────────────────────── */
.v-theme-toggle {
  background: none; border: 1px solid var(--v-border); border-radius: var(--v-radius-sm);
  padding: 9px 11px; cursor: pointer; color: var(--v-ink-2); line-height: 0;
}
.v-theme-toggle:hover { color: var(--v-green); border-color: var(--v-green); }
/* Cada icono aparece sólo en su tema: mostrar el sol en modo claro no le dice
   a nadie qué va a pasar si lo toca. */
.v-theme-toggle .v-theme-dark  { display: block; }
.v-theme-toggle .v-theme-light { display: none; }
:root[data-theme="dark"] .v-theme-toggle .v-theme-dark,
:root[data-theme="dark"] .v-theme-toggle .v-theme-light { display: none; }
:root[data-theme="dark"] .v-theme-toggle .v-theme-light { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .v-theme-toggle .v-theme-dark  { display: none; }
  :root:not([data-theme="light"]) .v-theme-toggle .v-theme-light { display: block; }
  :root[data-theme="light"] .v-theme-toggle .v-theme-dark  { display: block; }
  :root[data-theme="light"] .v-theme-toggle .v-theme-light { display: none; }
}

/* ── Estado de envío ─────────────────────────────────────────────────────── */
/* Un formulario que no avisa que está trabajando se aprieta dos veces. */
.v-btn.is-busy { position: relative; color: transparent !important; 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 rgba(255, 255, 255, .45); border-top-color: #fff;
  border-radius: 50%; animation: vSpin .6s linear infinite;
}
.v-btn-ghost.is-busy::after, .v-btn-light.is-busy::after {
  border-color: rgba(0, 0, 0, .2); border-top-color: var(--v-ink);
}
@keyframes vSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .v-btn.is-busy::after { animation-duration: 2s; }
}

/* ── Aviso de conexión ───────────────────────────────────────────────────── */
/* En piso de venta la señal se corta. Que la pantalla lo diga es la diferencia
   entre «está lento» y «no tengo señal». */
.v-offline {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: 80; display: none; align-items: center; gap: var(--v-sp-2);
  background: var(--v-deep); color: var(--v-on-deep);
  border-radius: 999px; padding: 11px 20px; font-size: 13px; font-weight: 700;
  box-shadow: var(--v-shadow-lg);
}
body.is-offline .v-offline { display: flex; }

/* ── Texto sólo para lectores de pantalla ────────────────────────────────────
 * Un `✓` es un símbolo, no una palabra. Quien navega con lector escucha «marca
 * de verificación» —o nada— donde debería escuchar «completada». Este es el
 * patrón estándar: sale del flujo visual sin salir del árbol de accesibilidad.
 * `display:none` NO sirve acá: eso lo saca también del lector.
 */
/* El texto para lectores de pantalla vive una sola vez, arriba, como
   `.v-sr-only`. Acá había una copia con otro nombre: dos clases idénticas
   compitiendo por el mismo trabajo es cómo empiezan los sistemas que nadie
   entiende. */

/* ── Utilidades que faltaban ─────────────────────────────────────────────── */
/* La escala de márgenes estaba a medias: existía `mb-4/5/6` y ningún `mt`, así
   que cualquier separación vertical hacia arriba volvía a caer en el `style`. */
.v-mb-2 { margin-bottom: var(--v-sp-2); }
.v-mb-3 { margin-bottom: var(--v-sp-3); }
.v-mt-1 { margin-top: var(--v-sp-1); }
.v-mt-2 { margin-top: var(--v-sp-2); }
.v-mt-3 { margin-top: var(--v-sp-3); }
.v-mt-4 { margin-top: var(--v-sp-4); }
.v-mt-5 { margin-top: var(--v-sp-5); }
.v-mt-6 { margin-top: var(--v-sp-6); }
.v-m0   { margin: 0; }
/* Hermano de `.v-fill-rest` para cuando el bloque NO tiene que crecer: sin
   `min-width:0` un nombre largo dentro de un flex se niega a encogerse y
   empuja al resto de la fila fuera de la tarjeta. */
.v-min-0 { min-width: 0; }
.v-center { justify-content: center; }
/* Negrita semántica del sistema: 700 es el único «fuerte» de la hoja. Evita
   que cada vista invente su propio `font-weight`. */
.v-strong { font-weight: 700; }

/* ── Texto: dos tamaños que faltaban ─────────────────────────────────────── */
/* `.v-text-lg` es el párrafo de lectura de una lección o una intro; `.v-note`
   es la aclaración al pie de una acción —13 px, apagada, nunca protagonista. */
.v-text-lg { font-size: 15px; color: var(--v-ink-2); line-height: 1.6; }
.v-note    { font-size: 13px; color: var(--v-muted); }
.v-emoji-sm { font-size: 18px; }

/* ── Enlace de regreso ───────────────────────────────────────────────────── */
/* Hermano de `.v-lesson-back`, pero para las páginas donde el enlace abre la
   vista en vez de vivir dentro de una barra: por eso trae su propio margen. */
.v-back {
  display: inline-flex; align-items: center; gap: var(--v-sp-1);
  font-size: 13px; font-weight: 700; color: var(--v-muted);
  margin-bottom: var(--v-sp-3);
}
.v-back:hover { color: var(--v-green); }

/* ── Botones e insignias: los tamaños que faltaban ───────────────────────── */
/* Existía `.v-btn-sm` y nada del otro lado. La acción principal de una página
   —«Solicitar mi evaluación»— necesita pesar más que un botón de fila. */
.v-btn-lg    { padding: 14px 26px; font-size: 15px; }
.v-btn-block { width: 100%; }
/* Una insignia que ES el resultado del curso no puede tener el mismo cuerpo
   que la etiqueta de una fila de tabla. */
.v-badge-lg  { font-size: 14px; padding: 11px 20px; }

/* ── Pie de tarjeta ──────────────────────────────────────────────────────── */
/* La acción secundaria de una tarjeta va separada por una línea, no por aire:
   sin la regla se lee como un ítem más de la lista de arriba. */
.v-card-foot {
  margin-top: var(--v-sp-5); padding-top: var(--v-sp-4);
  border-top: 1px solid var(--v-fill-2);
}

/* ── Curso: cabecera ─────────────────────────────────────────────────────── */
/* El título del curso es un `h1` pero no el de la plataforma: va un escalón
   por debajo de `.v-h1` para no competir con el nombre de la sección. */
.v-course-title {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 31px;
  text-transform: uppercase; margin: 4px 0 0;
}
/* El bloque de progreso se alinea a la derecha y reserva ancho: si se encoge
   con el texto, el porcentaje baila de posición entre curso y curso. */
.v-course-progress { min-width: 220px; text-align: right; }
.v-course-progress .v-badge { margin-bottom: var(--v-sp-2); }
.v-course-progress-count { display: block; margin: var(--v-sp-2) 0 var(--v-sp-1); }

/* Contenido y índice. La proporción 1.6/1 le da a la portada el peso que le
   corresponde sin dejar el índice en una columna de dos palabras de ancho. */
.v-course-layout { grid-template-columns: 1.6fr 1fr; gap: var(--v-sp-5); align-items: start; }

/* ── Curso: portada con velo ─────────────────────────────────────────────── */
/* Es pariente de `.v-hero` pero no es lo mismo: acá el velo baja en vertical
   —de transparente arriba a casi opaco abajo— porque el texto se apoya en el
   piso de la caja, no a la izquierda. */
.v-course-hero {
  position: relative; border-radius: var(--v-radius); overflow: hidden;
  background: var(--v-deep); aspect-ratio: 16 / 9;
  display: flex; align-items: center; justify-content: center;
}
.v-course-hero-media { position: absolute; inset: 0; }
.v-course-hero-veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(12, 59, 54, .30) 0%, rgba(12, 59, 54, .78) 100%);
}
.v-course-hero-body {
  position: relative; text-align: center; color: var(--v-on-deep); padding: var(--v-sp-6);
}
.v-course-letter {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 88px; line-height: 1;
}
/* El nombre de la fase, debajo de la letra. Va sobre el velo oscuro del
   recuadro, así que el color sale de `--v-on-deep-soft` y no del gris de
   cuerpo: ese gris sobre fondo oscuro no llega al contraste mínimo. */
.v-course-name {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 15px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--v-on-deep-soft);
  margin-top: 6px;
}
.v-course-summary {
  font-size: 15px; color: var(--v-on-deep-soft); line-height: 1.55;
  max-width: 520px; margin: 12px auto 22px;
}

/* ── Curso: índice de lecciones ──────────────────────────────────────────── */
/* Lista compacta: las filas se tocan casi entre sí a propósito, para que se
   lean como un solo recorrido y no como seis tarjetas sueltas. */
.v-toc { display: flex; flex-direction: column; gap: 4px; }
.v-toc-item {
  display: flex; align-items: center; gap: var(--v-sp-2);
  padding: 12px; border-radius: var(--v-radius-sm);
  transition: background .15s;
}
.v-toc-item:hover { background: var(--v-bg); }
.v-toc-title { flex: 1; font-size: 13px; font-weight: 600; color: var(--v-ink); line-height: 1.35; }
/* En el índice del curso hay más aire que en la barra de la lección, así que
   el disco puede crecer: mismo componente, otra escala. */
.v-lesson-num-lg { width: 26px; height: 26px; font-size: 12px; }

/* ── Lección: hoja de lectura ────────────────────────────────────────────── */
/* Ancho de lectura acotado: una línea de 1500 px obliga a barrer la cabeza de
   izquierda a derecha en cada renglón y se pierde el hilo. */
.v-lesson-doc { padding: 44px; max-width: 860px; margin: 0 auto; }

/* Aviso de la cápsula en pantallas chicas. Arranca oculto y lo enciende el JS
   sólo bajo 900 px: mostrarlo en escritorio es ruido, ahí ya se ve grande. */
.v-capsula-hint {
  display: none; font-size: 12px; color: var(--v-muted);
  margin: var(--v-sp-2) 0 0; text-align: center;
}

/* ── Evaluación práctica: piezas que faltaban ────────────────────────────── */
.v-practica-titulo { font-size: 26px; margin: 0 0 var(--v-sp-1); }
.v-rubrica-label   { font-size: 14px; color: var(--v-ink); }
/* Sin `min-width:0` un nombre largo estira la fila y rompe la grilla de dos
   columnas de la rúbrica. */
.v-rubrica-text    { min-width: 0; }

/* ── Inicio y malla: lo que faltaba para vaciar sus `style` ──────────────────
 * Todo lo de acá abajo salió de los 101 atributos `style` que tenían
 * `aula/dashboard.php` y `aula/malla.php`. No son utilidades sueltas: cada una
 * nombra una pieza que ya existía en el diseño y que las vistas venían
 * redibujando a mano, con un hex distinto cada vez.
 */

/* Texto — se suman a la familia `.v-title` / `.v-ink` que ya estaba. */
/* El titular de 15 px es el que usan las filas y las tarjetas chicas: `.v-title`
   pesa un punto más y ahí compite con el título de la sección. */
.v-title-sm { font-size: 15px; font-weight: 700; line-height: 1.35; color: var(--v-ink); }
/* Hermano de `.v-h1-lg`: mismo titular, un escalón más arriba, para el bloque
   que abre una sección dentro de la página. */
.v-h2-lg { font-size: 21px; }
/* El apagado que faltaba: `.v-ink` y `.v-accent` cubrían los extremos y para el
   gris del medio las vistas volvían a escribir `#7E938E`. */
.v-dim { color: var(--v-muted); }
/* El contador que acompaña a un título de tarjeta («3/5 listas»): es metadato,
   pero en negrita, porque es la cifra que se busca de un vistazo. */
.v-meta-strong { font-size: 12px; color: var(--v-muted); font-weight: 700; }
/* La bajada del saludo del inicio. Va un punto por encima de `.v-lead` y sin
   ancho máximo: comparte fila con la píldora de estado y ya está acotada. */
.v-page-lead { margin: 10px 0 0; font-size: 16px; color: var(--v-ink-2); }
/* El «ver todo» de una sección. No es un botón: es un enlace que pesa lo justo
   para encontrarse sin robarle protagonismo al contenido. */
.v-link-more { font-size: 14px; font-weight: 700; }
/* Faltaba el escalón intermedio de la escala de emoji. */
.v-emoji-md { font-size: 20px; }

/* Aviso con dos renglones: el segundo enumera y no debe pesar como el primero.
   Sólo cambia el tamaño porque el color lo pone la variante del aviso. */
.v-alert-detail { font-size: 13px; margin-top: 2px; }

/* KPI */
/* Sobre la tarjeta oscura `--v-ink-2` está calculado para fondo claro y el pie
   del KPI se pierde: ahí manda el gris de marca. */
.v-kpi-note.is-on-dark { color: var(--v-muted); }
/* El denominador de un KPI («/12»): parte del mismo número, pero es el techo,
   no el logro, así que no compite en tamaño ni en color. */
.v-kpi-total { font-size: 30px; color: var(--v-muted-2); }

/* Inicio: continuar donde quedaste */
/* El rótulo del bloque. No es `.v-kicker`: aquel abre la página, este abre una
   tarjeta y por eso respira menos. */
.v-continue-head {
  font-family: 'Archivo', sans-serif; font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--v-green); font-weight: 700;
  margin-bottom: var(--v-sp-3);
}
.v-continue-track { font-size: 12px; color: var(--v-muted); font-weight: 600; }

/* Inicio: resumen de la malla */
/* El nombre de la línea empuja al resto de la fila hacia la derecha y se recorta
   antes que romperla. */
.v-line-row-name {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 14px; font-weight: 600; color: var(--v-ink);
}

/* Malla */
/* La primera sección de la página no separa de nada: los 38 px de `.v-section-head`
   están pensados para el aire ENTRE bloques. */
.v-section-head.is-first { margin-top: var(--v-sp-2); }
/* El emoji que encabeza cada tarjeta de la portada. */
.v-hero-card-emoji { font-size: 22px; margin-bottom: 8px; }
/* Título y resumen de la tarjeta de fase: son el par que se lee al escanear la
   fila de cinco, y por eso no comparten estilo con los títulos de sección. */
.v-phase-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 19px;
  text-transform: uppercase; margin: var(--v-sp-3) 0 var(--v-sp-1);
}
.v-phase-summary { font-size: 13px; line-height: 1.45; color: var(--v-ink-2); margin: 0 0 var(--v-sp-4); }
/* El pie de la tarjeta: cuántas lecciones van, o qué falta para desbloquearla. */
.v-phase-foot { font-size: 11px; color: var(--v-muted); margin-top: var(--v-sp-2); font-weight: 600; }

/* Composición */
/* La proporción del inicio: el bloque de «continuar» manda y Vity acompaña.
   Estaba escrita en el `style` de la vista, que es exactamente lo que obligaba
   al `!important` de la versión angosta. */
.v-grid-split { grid-template-columns: 1.5fr 1fr; }
/* Botón que ocupa el ancho de su tarjeta porque es su única acción. */
.v-btn-block { width: 100%; }
/* Una tarjeta que además es enlace: `<a>` es inline por defecto y sin esto la
   caja se encoge hasta el ancho del texto. */
a.v-card, a.v-card-dark { display: block; }

/* (v-mb-2, v-mb-3 y v-mt-4 ya están declaradas más arriba) */


/* ── Formularios: cabecera y envío ───────────────────────────────────────── */
/* El emoji que titula un bloque de formulario. No es contenido —va con
   `aria-hidden`— así que no puede heredar el tamaño del texto de al lado. */
.v-form-head-icon { font-size: 20px; flex: 0 0 auto; line-height: 1; }
/* La bajada que explica para qué sirve el bloque. Vivía inline en los cuatro
   formularios de la cuenta, cada uno con su propio margen. */
.v-form-head-note { margin: 2px 0 0; font-size: 13px; color: var(--v-muted); }
/* El botón que cierra un formulario necesita despegarse de los campos: pegado
   al último `input` se lee como parte del campo, no como la acción. */
.v-form-submit { margin-top: var(--v-sp-5); }

/* ── Grupos de casillas ──────────────────────────────────────────────────── */
/*
 * `fieldset` + `legend` es lo que le dice a un lector de pantalla que las tres
 * casillas de «De qué» son UNA pregunta y no tres preguntas sueltas. Antes el
 * encabezado era un `<div>`: se veía igual y no significaba nada.
 *
 * El navegador le pone al `fieldset` borde, padding y un `min-width` propios;
 * se los sacamos porque acá quien agrupa a la vista es la grilla.
 */
.v-fieldset { border: none; margin: 0; padding: 0; min-width: 0; }
.v-fieldset + .v-fieldset { margin-top: var(--v-sp-5); }
.v-legend { padding: 0; margin-bottom: var(--v-sp-2); }

/* ── Tarjeta apagada ─────────────────────────────────────────────────────── */
/* Para el bloque que se muestra pero no se toca —la ficha laboral—. Se funde
   con el fondo de la página a propósito: la señal de «esto no es tuyo» es que
   no tiene el papel blanco que sí tienen los formularios de arriba.
   Reemplaza un `style="background:var(--v-mist)"` que apuntaba a un token
   inexistente, así que la tarjeta venía quedando transparente por accidente. */
.v-card-muted { background: var(--v-bg); }

/* ── Mi cuenta ───────────────────────────────────────────────────────────── */
/* Los cuatro bloques de la cuenta son hermanos y se separan igual. Cada uno
   traía su `margin-bottom` inline: bastaba con que alguien escribiera 24 en
   uno para que la columna se viera desprolija. */
.v-account-section { margin-bottom: var(--v-sp-5); }

/* Cabecera de identidad: foto, nombre y las dos insignias del juego. Envuelve
   en pantalla angosta para que las insignias bajen enteras en vez de
   comprimir el nombre hasta partirlo. */
.v-identity { display: flex; align-items: center; gap: var(--v-sp-5); flex-wrap: wrap; }
/* La foto de la cuenta es la más grande de la plataforma: es de quien mira. */
.v-avatar-lg { width: 76px; height: 76px; font-size: 25px; }
.v-identity-name {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 22px; color: var(--v-ink);
}
.v-identity-role { font-size: 13px; color: var(--v-muted); margin-top: 3px; }

/* ── Ingreso ─────────────────────────────────────────────────────────────── */
/*
 * Dos columnas: la foto de tienda a la izquierda y el formulario a la derecha.
 * Todo esto vivía en un `<style>` dentro de la vista, con nueve `#hex` escritos
 * a mano —o sea: la única pantalla de la plataforma que jamás iba a acompañar
 * un cambio de paleta era justo la primera que ve alguien.
 *
 * La foto no es decoración: ubica la plataforma en el mundo real de quien entra
 * desde el celular, parado en el piso de venta.
 */
.v-login { display: flex; min-height: 100vh; }
.v-login-art {
  flex: 1; position: relative; overflow: hidden;
  display: flex; align-items: flex-end; padding: 56px;
  background: var(--v-deep);
}
.v-login-photo {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .42;
}
/* Velo vertical: sin él el texto blanco cae sobre la parte clara de la foto. */
.v-login-veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(12, 59, 54, .55) 0%, rgba(12, 59, 54, .95) 100%);
}
.v-login-copy { position: relative; color: var(--v-on-deep); max-width: 520px; }
.v-login-tag { display: flex; align-items: center; gap: 8px; margin-bottom: 20px; }
.v-login-rule { width: 28px; height: 2px; background: var(--v-green); flex: 0 0 auto; }
.v-login-lockup { display: flex; align-items: center; gap: 18px; }
.v-login-mark {
  width: 92px; height: 92px; flex: 0 0 auto; border-radius: 50%; background: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .26);
}
.v-login-mark img { display: block; }
.v-login-name {
  font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 40px;
  color: #fff; line-height: 1;
}
.v-login-sub {
  font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 13px;
  letter-spacing: .5em; color: var(--v-lime); margin-top: 5px;
}
.v-login-claim {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 46px;
  line-height: 1.04; margin: 28px 0 14px;
}
.v-login-lead {
  font-size: 16px; line-height: 1.6; color: var(--v-on-deep-soft);
  margin: 0; max-width: 470px;
}
.v-login-legal { margin-top: 38px; font-size: 12px; color: var(--v-muted); }

.v-login-form {
  width: min(520px, 100%); flex: 0 0 auto; background: var(--v-surface);
  display: flex; align-items: center; padding: 56px;
}
.v-login-box { width: 100%; max-width: 380px; margin: 0 auto; }
.v-login-title {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 32px;
  text-transform: uppercase; margin: 0 0 8px;
}
.v-login-note { font-size: 14px; color: var(--v-ink-2); margin: 0 0 28px; }
.v-login-help { margin-top: 20px; text-align: center; }

/* «Mantener mi sesión abierta». El aviso del equipo compartido va SIEMPRE
   visible debajo de la casilla, nunca detrás de un ícono de ayuda: se tiene que
   leer antes de marcar, no después de averiguar. */
.v-login-recordar { margin: 4px 0 18px; }
.v-recordar-fila {
  display: flex; align-items: center; gap: 10px;
  font-size: 14px; cursor: pointer;
}
.v-recordar-fila input { width: 17px; height: 17px; accent-color: var(--v-green); flex: 0 0 auto; }
.v-login-recordar .v-field-hint { margin-top: 6px; display: block; }

/* Bajo 900 px la foto se va: en un teléfono, media pantalla de fotografía es
   media pantalla menos para el único formulario que importa acá. */
@media (max-width: 900px) {
  .v-login-art { display: none; }
  .v-login-form { width: 100%; padding: 32px 24px; }
}

/* ── Pantalla suelta de autenticación ────────────────────────────────────── */
/* Una tarjeta centrada sobre el verde de marca, sin sidebar ni cabecera: son
   las pantallas donde todavía no hay sesión completa —definir la contraseña
   provisoria— y cualquier navegación sería una salida en falso. */
.v-auth-screen {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; background: var(--v-deep);
}
.v-auth-card { width: 100%; max-width: 440px; padding: 36px 38px; }
.v-auth-title {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 26px;
  text-transform: uppercase; margin: 0 0 8px;
}
.v-auth-note { font-size: 14px; color: var(--v-ink-2); margin: 0 0 24px; }
.v-auth-foot { text-align: center; margin-top: var(--v-sp-4); }
.v-auth-out { font-size: 13px; color: var(--v-muted); }
.v-auth-out:hover { color: var(--v-green); }
/* Los formularios de autenticación cierran con un botón a todo el ancho y muy
   pegado: no hay nada más en la tarjeta de lo que separarlo. */
.v-auth-submit { width: 100%; margin-top: var(--v-sp-1); }

/* ── Pantalla de carga ───────────────────────────────────────────────────── */
/*
 * Vivía completa en un `<style>` dentro de `partials/splash.php`. Los tiempos,
 * los retardos y las curvas son EXACTAMENTE los del prototipo: la secuencia
 * dura 2,4 s y cada pieza entra donde tiene que entrar. No se tocó ni un valor
 * al traerla; lo único que cambió son los `#hex`, que ahora son tokens.
 */
#v-splash {
  position: fixed; inset: 0; z-index: 200; background: var(--v-deep);
  display: flex; align-items: center; justify-content: center;
  animation: vSplashOut 2.4s ease forwards;
}
/* Apenas empieza el desvanecido la capa deja de interceptar clics: sin esto la
   primera interacción del asesor no responde durante medio segundo. */
.v-splash-done { pointer-events: none; }

.v-splash-grain {
  position: absolute; inset: 0; opacity: .1;
  background-image: repeating-linear-gradient(115deg, var(--v-green) 0 2px, transparent 2px 30px);
}
.v-splash-halo {
  position: absolute; width: 560px; height: 560px; border-radius: 50%;
  background: radial-gradient(circle, rgba(20, 160, 122, .30) 0%, rgba(20, 160, 122, 0) 68%);
  animation: vBreath 3.2s ease-in-out infinite;
}
.v-splash-stack { position: relative; display: flex; flex-direction: column; align-items: center; }

.v-splash-mark { position: relative; width: 188px; height: 188px; }
.v-splash-ring { position: absolute; inset: 0; }
.v-splash-track { stroke: rgba(20, 160, 122, .35); stroke-width: 2; }

/* 572 ≈ 2πr con r=91. El trazo arranca oculto y se dibuja entero. */
.v-splash-arc {
  stroke: var(--v-lime); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 572; stroke-dashoffset: 572;
  animation: vDraw 1.5s cubic-bezier(.45, .05, .2, 1) .25s forwards;
}

.v-splash-disc {
  position: absolute; inset: 20px; border-radius: 50%; background: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .28);
  animation: vMarkIn .8s cubic-bezier(.2, .9, .3, 1) both, vFloat 3.4s ease-in-out 1.2s infinite;
}
.v-splash-disc img { display: block; animation: vLogoIn .9s cubic-bezier(.2, .9, .3, 1) .18s both; }

.v-splash-bar {
  width: 260px; height: 4px; border-radius: 99px; background: var(--v-deep-2);
  overflow: hidden; margin-top: 40px; animation: vRise .6s ease 1s both;
}
.v-splash-bar > span {
  display: block; width: 100%; height: 100%; background: var(--v-lime);
  animation: vBar 1.5s cubic-bezier(.5, 0, .2, 1) 1s both;
}
.v-splash-text {
  margin-top: 20px; font-family: 'Archivo', sans-serif; font-weight: 700;
  font-size: 12px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--v-on-deep-soft);
  animation: vRise .6s ease 1.15s both;
}

@keyframes vDraw   { to { stroke-dashoffset: 0; } }
@keyframes vMarkIn { 0% { opacity: 0; transform: scale(.72); } 100% { opacity: 1; transform: scale(1); } }
@keyframes vLogoIn { 0% { opacity: 0; transform: scale(.6) rotate(-14deg); } 100% { opacity: 1; transform: none; } }
@keyframes vFloat  { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE
   Buena parte del equipo entra desde el celular, en piso de venta. El móvil no
   es una degradación del escritorio: es el caso principal.
   ═══════════════════════════════════════════════════════════════════════════ */

.v-burger {
  display: none; background: none; border: 1px solid var(--v-border);
  border-radius: var(--v-radius-sm); padding: 9px 11px; cursor: pointer;
  color: var(--v-ink); line-height: 0;
}
.v-scrim { display: none; position: fixed; inset: 0; z-index: 45; background: rgba(16, 26, 36, .5); }

/* Red de seguridad: nada desborda el ancho de la pantalla, incluido el
   contenido con ancho fijo que se agregue más adelante. */
img, svg, video, iframe { max-width: 100%; }

/* ── Escritorio angosto ──────────────────────────────────────────────────── */
@media (max-width: 1180px) {
  .v-grid-5 { grid-template-columns: repeat(3, 1fr); }
  .v-grid-4 { grid-template-columns: repeat(2, 1fr); }
}

/* ── Tablet ──────────────────────────────────────────────────────────────── */
@media (max-width: 960px) {
  /* El sidebar NO se oculta: pasa a ser un cajón. Ocultarlo sin alternativa
     dejaba la plataforma sin ninguna navegación. */
  .v-sidebar {
    position: fixed; top: 0; left: 0; z-index: 50;
    transform: translateX(-100%); transition: transform .25s cubic-bezier(.2,.8,.2,1);
    box-shadow: 8px 0 40px rgba(0, 0, 0, .3);
  }
  body.v-nav-open .v-sidebar { transform: none; }
  body.v-nav-open .v-scrim  { display: block; }
  body.v-nav-open { overflow: hidden; }

  .v-burger { display: inline-flex; align-items: center; }
  .v-header { padding: 0 16px; gap: 12px; }
  .v-search { max-width: none; margin-left: 0; }
  .v-page-title { display: none; }
  .v-content { padding: 24px 20px 44px; }

  .v-hero-body { padding: 20px 22px; gap: 22px; }
  .v-continue-letter { width: 92px; height: 92px; font-size: 48px; }

  .v-grid-2, .v-grid-3, .v-grid-4, .v-grid-5 { grid-template-columns: repeat(2, 1fr); }

  /* Las grillas de proporción ya no viven en el atributo `style` sino en clases
     como `.v-grid-split`, así que el `!important` dejó de ser obligatorio. Se
     mantiene a propósito: cubre de una sola vez cualquier proporción que se
     agregue después y evita tener que enumerarlas acá una por una. */
  .v-container > .v-grid,
  .v-container-narrow > .v-grid { grid-template-columns: 1fr !important; }
}

/* ── Celular ─────────────────────────────────────────────────────────────── */
@media (max-width: 680px) {
  .v-header { height: 62px; padding: 0 14px; gap: 10px; }
  .v-content { padding: 18px 14px 40px; }

  /* ── Búsqueda en celular ──────────────────────────────────────────────────
   * Antes acá decía `display:none` y la justificación era «la búsqueda vive en
   * el banco». No es cierta: para buscar había que abrir el menú, entrar al
   * banco y recién ahí escribir. Tres toques para lo que es la acción más
   * frecuente de alguien parado frente a un cliente.
   *
   * Ahora la barra se colapsa en un botón de lupa y se despliega como una fila
   * completa bajo el encabezado. Sigue siendo el mismo formulario: un solo
   * campo, un solo destino.
   */
  .v-search-toggle {
    display: inline-flex; align-items: center; background: none;
    border: 1px solid var(--v-border); border-radius: var(--v-radius-sm);
    padding: 9px 11px; cursor: pointer; color: var(--v-ink); line-height: 0;
  }
  .v-search {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    margin: 0; max-width: none; border-radius: 0;
    border-left: none; border-right: none; padding: 12px 14px;
  }
  body.v-search-open .v-search { display: flex; }
  /* 16px o iOS hace zoom al enfocar y descuadra todo el encabezado. */
  .v-search input { font-size: 16px; }
  .v-header { position: sticky; }

  /* Las tarjetas con contenido (cursos, documentos) van a una columna: apiladas
     se leen; en dos quedan ilegibles. Los KPI son lo contrario —un número y una
     etiqueta— así que se quedan en 2×2 y el tablero se ve de un vistazo en vez
     de obligar a scrollear cuatro pantallas para leer cuatro cifras. */
  .v-grid, .v-grid-2, .v-grid-3, .v-grid-5 { grid-template-columns: 1fr !important; gap: 14px; }
  .v-grid-4 { grid-template-columns: repeat(2, 1fr) !important; gap: 12px; }
  .v-grid-4 > .v-card, .v-grid-4 > .v-card-dark, .v-grid-4 > a.v-card { padding: 15px 14px; }
  .v-grid-4 .v-kpi-label { font-size: 10px; letter-spacing: .1em; }
  .v-grid-4 .v-kpi-value { font-size: 30px; }
  .v-grid-4 .v-kpi-value span { font-size: 20px; }
  .v-grid-4 .v-kpi-note, .v-grid-4 .v-card > div:last-child { font-size: 11px; line-height: 1.35; }

  .v-card, .v-card-dark { padding: 18px; }
  .v-card-gradient { padding: 20px; }

  .v-h1     { font-size: 24px; }
  .v-h1-lg  { font-size: 26px; line-height: 1.12; }
  .v-h1-sm  { font-size: 22px; }
  .v-h1-xs  { font-size: 20px; }
  .v-h2     { font-size: 17px; }
  .v-h3     { font-size: 15px; }
  .v-lead   { font-size: 14px; }
  .v-kicker { font-size: 11px; }

  .v-kpi-value    { font-size: 38px; letter-spacing: -1px; }
  .v-phase-letter { font-size: 40px; }
  .v-phase        { min-height: 0; }

  /* Altura de dedo: 46 px es el mínimo cómodo en piso de venta, muchas veces
     con el celular en una mano. */
  .v-btn    { width: 100%; justify-content: center; padding: 14px 18px; min-height: 46px; }
  .v-btn-sm { width: auto; min-height: 40px; padding: 10px 14px; }

  .v-drawer { width: 100%; }
  .v-section-head { flex-wrap: wrap; gap: 8px; margin: 26px 0 14px; }
  .v-section-rule { display: none; }
  .v-empty { padding: 36px 16px; }

  /* Las tablas se leen de a una fila. En 375 px, seis columnas no entran ni
     con scroll horizontal cómodo: hay que girar el teléfono para leer un
     nombre, y nadie lo hace. */
  .v-table-stack thead { display: none; }
  .v-table-stack, .v-table-stack tbody { display: block; }
  .v-table-stack tr {
    display: block; background: #fff; border: 1px solid var(--v-border);
    border-radius: 12px; padding: 12px 14px; margin-bottom: 10px;
  }
  .v-table-stack td {
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px; padding: 7px 0; border: none; text-align: right;
  }
  .v-table-stack td::before {
    content: attr(data-label); flex: 0 0 auto; text-align: left;
    font-family: 'Archivo', sans-serif; font-size: 10px; letter-spacing: .1em;
    text-transform: uppercase; color: var(--v-muted); font-weight: 700;
  }
  .v-table-stack td:first-child {
    border-bottom: 1px solid var(--v-fill-2); padding-bottom: 12px; margin-bottom: 4px;
  }
  .v-table-stack td:first-child::before { display: none; }
}

/* ── Celular: componentes ────────────────────────────────────────────────── */
@media (max-width: 680px) {
  .v-page-head-split { gap: var(--v-sp-3); margin-bottom: 20px; }

  /* La cabecera del inicio: el saludo arriba, la píldora debajo y a la
     izquierda. Estirada a lo ancho parece un botón, y no lo es. */
  .v-page-head-split .v-pill { align-self: flex-start; }

  .v-continue { padding: 18px; }
  .v-continue-body { gap: var(--v-sp-3); }
  .v-continue-letter { width: 100%; height: 84px; font-size: 44px; }
  .v-continue-main { min-width: 0; }
  .v-continue-title { font-size: 19px; }

  .v-hero-body { padding: 18px; gap: var(--v-sp-4); }
  .v-hero-intro { max-width: none; }
  .v-hero-cards { grid-template-columns: 1fr; gap: var(--v-sp-2); }
  .v-hero-band { height: 148px; }
  .v-hero-band-body { left: 18px; bottom: 18px; right: 18px; }
  .v-hero-band-title { font-size: 18px; }

  .v-level { gap: var(--v-sp-4); }
  .v-level-pts { font-size: 34px; }
  .v-streak { padding: 0; display: flex; align-items: center; gap: var(--v-sp-2); }
  .v-streak-days { font-size: 20px; }

  /* Las insignias en dos columnas: en una sola quedan cuatro pantallas de
     scroll para ver ocho iconos. */
  .v-badge-grid { grid-template-columns: repeat(2, 1fr) !important; }

  .v-item-row { gap: var(--v-sp-3); flex-wrap: wrap; }
  .v-item-icon { width: 48px; height: 48px; font-size: 26px; border-radius: 11px; }
  .v-item-icon-alt { width: 48px; height: 48px; font-size: 26px; }
  .v-live-row { padding: 18px; gap: var(--v-sp-3); }
  /* El botón de la fila ocupa el ancho: es la acción de la tarjeta. */
  .v-item-row > .v-btn { width: 100%; }

  .v-next-live { padding: 16px 18px; flex-wrap: wrap; }
  .v-next-live-cta { width: 100%; text-align: center; }

  .v-doc-cover { margin: -18px -18px 16px; height: 92px; }

  /* Estos tres paddings antes viajaban en el atributo `style`, así que ninguna
     media query podía tocarlos: 40 px de aire lateral en una pantalla de 375
     dejaban la columna de texto en la mitad del ancho. */
  .v-doc-page { padding: 18px; }
  .v-verify-shell { padding: var(--v-sp-3); }
  .v-verify-card  { padding: var(--v-sp-4); }

  .v-doc-meta { gap: var(--v-sp-2) var(--v-sp-3); }
  .v-ask-vity { gap: var(--v-sp-3); }

  .v-lesson-bar { gap: var(--v-sp-2); margin-bottom: var(--v-sp-3); }
  /* El índice de lecciones scrollea; que se note dónde termina. */
  .v-lesson-tabs { margin: 0 -14px; padding: 0 14px 4px; }
  .v-lesson-bar > .v-btn-sm { width: auto; }
  .v-lesson-doc { padding: 20px; }

  /* Apilado, el bloque de progreso deja de ser una columna: alinear a la
     derecha un texto que ahora ocupa todo el ancho lo deja huérfano. */
  .v-course-progress { min-width: 0; text-align: left; }
  .v-course-title { font-size: 22px; }
  .v-course-hero-body { padding: var(--v-sp-4); }
  .v-course-letter { font-size: 54px; }
  .v-course-summary { font-size: 14px; margin: var(--v-sp-2) auto var(--v-sp-4); }

  .v-rank-row { padding: 12px 14px; gap: var(--v-sp-2); }
  .v-rank-pts { font-size: 17px; }

  .v-drawer-head { padding: 16px 18px; }
  .v-drawer-body { padding: 18px 16px; }
  .v-offline { bottom: 12px; font-size: 12px; padding: 10px 16px; }
}

@media (max-width: 400px) {
  .v-content { padding: 16px 12px 36px; }
  .v-h1, .v-h1-lg { font-size: 22px; }
  .v-kpi-value { font-size: 32px; }
  .v-card, .v-card-dark { padding: 15px; }
  .v-badge-grid { grid-template-columns: repeat(2, 1fr) !important; }
}

/* ── Diploma ─────────────────────────────────────────────────────────────────
 * ATENCIÓN: este bloque NO usa los tokens del tema, y es a propósito.
 *
 * Un diploma es un documento: se imprime, se adjunta a un correo, se sube a
 * LinkedIn. El papel es blanco siempre. Si la lámina siguiera `--v-surface` y
 * `--v-ink`, quien tuviera el modo oscuro activado se descargaría un PDF negro
 * con letras claras y lo mandaría así a Talento Humano.
 *
 * Por eso los valores acá están escritos literales y quietos. Es la única
 * excepción de la hoja, y existe para que el documento sea el mismo en toda
 * pantalla y en toda impresora.
 * ─────────────────────────────────────────────────────────────────────────── */
.v-diploma-modal {
  position: fixed; inset: 0; z-index: 70;
  display: flex; align-items: center; justify-content: center; padding: 22px;
}
.v-diploma-scrim { position: absolute; inset: 0; background: rgba(16, 26, 36, .62); }
.v-diploma-box {
  position: relative; width: 1080px; max-width: 100%; height: 100%;
  display: flex; flex-direction: column; animation: erPop .25s ease;
}

.v-diploma-actions {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px; color: #fff; flex-wrap: wrap;
}
.v-diploma-actions-title {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 16px; margin-right: auto;
}
.v-diploma-close {
  background: rgba(255, 255, 255, .14); border: none; color: #fff;
  cursor: pointer; padding: 8px; line-height: 0; border-radius: 9px; flex: 0 0 auto;
}
.v-diploma-close:hover { background: rgba(255, 255, 255, .24); }
.v-diploma-actions :where(a, button):focus-visible { outline-color: #fff; }
.v-btn-linkedin { background: #0A66C2; color: #fff; }
.v-btn-linkedin:hover { color: #fff; }
/* Un enlace que todavía no tiene destino no debe parecer disponible. */
.v-diploma-actions [aria-disabled="true"] { opacity: .5; cursor: default; }

.v-diploma-stage { flex: 1; min-height: 0; position: relative; }

.v-diploma-sheet {
  position: absolute; top: 0; left: 50%; width: 1080px;
  transform-origin: top center; background: #fff; border-radius: 6px;
  overflow: hidden; box-shadow: 0 30px 80px rgba(0, 0, 0, .4); display: flex;
}
.v-diploma-accent { width: 9px; flex: 0 0 auto; background: #14A07A; }
.v-diploma-body { flex: 1; min-width: 0; padding: 8px; }
.v-diploma-frame { border: 1px solid #DDE7E3; padding: 44px; display: flex; gap: 44px; flex-wrap: wrap; }

.v-diploma-main { flex: 2 1 420px; min-width: 0; }
.v-diploma-kicker {
  font-family: 'Archivo', sans-serif; font-size: 10px; letter-spacing: .3em;
  text-transform: uppercase; color: #7E938E; font-weight: 600; margin-bottom: 10px;
}
.v-diploma-brand { display: flex; align-items: center; gap: 14px; }
.v-diploma-brand img { display: block; }
.v-diploma-brand-name {
  font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 28px;
  color: #0C3B36; line-height: 1;
}
.v-diploma-brand-sub {
  font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 10px;
  letter-spacing: .46em; color: #14A07A; margin-top: 3px;
}
.v-diploma-rule { width: 58px; height: 3px; background: #14A07A; margin: 26px 0 30px; }

.v-diploma-lead { font-size: 15px; color: #5C6B67; }
.v-diploma-lead-2 { margin-top: 26px; }
.v-diploma-person {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 44px;
  line-height: 1.1; color: #10302B; margin: 10px 0 6px;
}
.v-diploma-id { font-size: 13px; color: #7E938E; }
.v-diploma-title { font-size: 23px; font-weight: 800; color: #10302B; margin: 8px 0 12px; line-height: 1.3; }
.v-diploma-summary { font-size: 14px; color: #5C6B67; line-height: 1.6; max-width: 560px; }

.v-diploma-signs { display: flex; gap: 44px; margin-top: 48px; flex-wrap: wrap; }
.v-diploma-sign { flex: 1; min-width: 200px; }
.v-diploma-sign-name {
  font-family: Georgia, 'Times New Roman', serif; font-style: italic;
  font-size: 21px; color: #10302B; margin-bottom: 4px;
}
.v-diploma-sign-rule { height: 1px; background: #10302B; margin-bottom: 8px; }
.v-diploma-sign-role { font-size: 12px; color: #5C6B67; }

.v-diploma-aside {
  flex: 1 1 260px; min-width: 0; border-left: 1px solid #DDE7E3;
  padding-left: 40px; display: flex; flex-direction: column; align-items: center;
}
.v-diploma-aside-head {
  align-self: stretch; text-align: right; font-family: 'Archivo', sans-serif;
  font-size: 13px; letter-spacing: .3em; text-transform: uppercase;
  color: #10302B; font-weight: 600; line-height: 2;
}
.v-diploma-seal {
  width: 158px; height: 158px; border: 2px solid #14A07A; border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  margin: 34px 0 30px; color: #14A07A;
}
.v-diploma-seal svg { margin-bottom: 10px; }
.v-diploma-seal-label {
  font-family: 'Archivo', sans-serif; font-size: 10px; letter-spacing: .18em; font-weight: 700;
}
.v-diploma-seal-year {
  font-family: 'Archivo', sans-serif; font-size: 14px; letter-spacing: .14em;
  font-weight: 700; margin-top: 3px;
}
.v-diploma-qr { width: 168px; height: auto; display: block; }
.v-diploma-qr-note { font-size: 12px; color: #5C6B67; text-align: center; margin-top: 14px; line-height: 1.6; }
.v-diploma-code {
  font-family: 'Archivo', sans-serif; font-size: 14px; font-weight: 700;
  color: #10302B; letter-spacing: .04em; margin-top: 12px;
}
.v-diploma-state { margin-top: 14px; }
/* El estado va con palabra Y color. Quien no distingue el verde del ámbar
   tiene que poder leer si el certificado sigue vigente. */
.v-diploma-state-tag { font-size: 11px; font-weight: 700; padding: 4px 12px; border-radius: 99px; }
.v-diploma-state-tag.is-vigente  { color: #0B6B58; background: #E1EFE9; }
.v-diploma-state-tag.is-vencido  { color: #A8790F; background: #FBF1D8; }
.v-diploma-state-tag.is-revocado { color: #A32020; background: #FBEAEA; }

.v-diploma-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 16px 48px 22px; border-top: 1px solid #DDE7E3; margin: 0 8px;
  font-size: 12px; color: #7E938E; flex-wrap: wrap;
}

@media (max-width: 680px) {
  .v-diploma-modal { padding: 12px; }
  .v-diploma-actions { gap: 8px; margin-bottom: 10px; }
  .v-diploma-actions-title { flex: 1 0 100%; margin-right: 0; font-size: 14px; }
  /* Los botones de acción NO se estiran acá: son tres en una fila y el ancho
     completo los apilaría, empujando la lámina fuera de la pantalla. */
  .v-diploma-actions .v-btn { width: auto; }
}

/* ── Recorrido guiado ─────────────────────────────────────────────────────────
 * Se muestra una sola vez, en el inicio, la primera vez que alguien entra.
 *
 * El foco se resalta con un `box-shadow` enorme sobre un recuadro transparente:
 * oscurece TODA la pantalla menos el elemento del que se está hablando, sin
 * tener que clonar ese elemento ni recortar nada. Un clon se desincroniza; el
 * hueco no.
 * ─────────────────────────────────────────────────────────────────────────── */
.v-tour { position: fixed; inset: 0; z-index: 90; }

.v-tour-spot {
  position: absolute; border-radius: 12px; pointer-events: none;
  box-shadow: 0 0 0 9999px rgba(6, 26, 23, .78), 0 0 0 3px var(--v-green);
  transition: top .28s cubic-bezier(.2,.8,.2,1), left .28s cubic-bezier(.2,.8,.2,1),
              width .28s cubic-bezier(.2,.8,.2,1), height .28s cubic-bezier(.2,.8,.2,1);
}
/* Pasos sin elemento que señalar —la bienvenida y el cierre—: el hueco se
   colapsa en el centro y queda sólo el velo. */
.v-tour-spot.is-blank { box-shadow: 0 0 0 9999px rgba(6, 26, 23, .82); border-radius: 0; }

.v-tour-card {
  position: absolute; width: min(370px, calc(100vw - 32px));
  background: var(--v-surface); border-radius: var(--v-radius);
  box-shadow: var(--v-shadow-lg); padding: 24px 26px;
  transition: top .28s cubic-bezier(.2,.8,.2,1), left .28s cubic-bezier(.2,.8,.2,1);
}
/* La flecha que ata la tarjeta con lo que señala. Sin ella, en una pantalla
   grande la tarjeta parece un cartel suelto. */
.v-tour-card::before {
  content: ''; position: absolute; width: 14px; height: 14px;
  background: var(--v-surface); transform: rotate(45deg);
}
.v-tour-card[data-arrow="up"]::before    { top: -7px;    left: var(--arrow-x, 32px); }
.v-tour-card[data-arrow="down"]::before  { bottom: -7px; left: var(--arrow-x, 32px); }
.v-tour-card[data-arrow="left"]::before  { left: -7px;   top: var(--arrow-y, 32px); }
.v-tour-card[data-arrow="right"]::before { right: -7px;  top: var(--arrow-y, 32px); }
.v-tour-card[data-arrow="none"]::before  { display: none; }

.v-tour-emoji { font-size: 34px; line-height: 1; display: block; margin-bottom: var(--v-sp-2); }
.v-tour-title {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 19px;
  text-transform: uppercase; margin: 0 0 8px; color: var(--v-ink); line-height: 1.2;
}
.v-tour-text { font-size: 14px; line-height: 1.6; color: var(--v-ink-2); margin: 0; }

.v-tour-foot {
  display: flex; align-items: center; gap: var(--v-sp-2);
  margin-top: var(--v-sp-5); padding-top: var(--v-sp-3);
  border-top: 1px solid var(--v-fill-2);
}
.v-tour-dots { display: flex; gap: 6px; margin-right: auto; }
.v-tour-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--v-border);
  transition: background .2s, transform .2s;
}
.v-tour-dot.is-current { background: var(--v-green); transform: scale(1.35); }
.v-tour-dot.is-done    { background: var(--v-muted-2); }

.v-tour-skip {
  background: none; border: none; cursor: pointer; font-family: inherit;
  font-size: 13px; font-weight: 700; color: var(--v-muted); padding: 8px 4px;
}
.v-tour-skip:hover { color: var(--v-ink-2); }

@media (max-width: 680px) {
  /* En celular la tarjeta deja de perseguir al elemento y se ancla abajo: con
     370 px de tarjeta sobre 375 px de pantalla, «al lado de» no existe. El
     hueco iluminado sigue marcando de qué se está hablando. */
  .v-tour-card {
    position: fixed; left: 12px !important; right: 12px;
    bottom: 12px; top: auto !important; width: auto;
    padding: 20px; animation: erFade .25s ease;
  }
  .v-tour-card::before { display: none; }
  .v-tour-title { font-size: 17px; }
  .v-tour-foot { margin-top: var(--v-sp-4); }
  .v-tour-foot .v-btn { min-height: 42px; padding: 11px 18px; }
}

/* Quien pidió menos movimiento no quiere que el foco se deslice por la
   pantalla en cada paso. */
@media (prefers-reduced-motion: reduce) {
  .v-tour-spot, .v-tour-card { transition: none; }
}

/* ── Pie de la plataforma ──────────────────────────────────────────────────── */
.v-footer {
  margin-top: var(--v-sp-6);
  padding-top: var(--v-sp-5);
  border-top: 1px solid var(--v-border);
}
.v-footer-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--v-sp-4); flex-wrap: wrap;
  font-size: 12.5px; color: var(--v-muted);
}
.v-footer-inner p { margin: 0; }
.v-footer-brand strong { color: var(--v-ink-2); font-weight: 700; }
.v-footer-links { display: flex; align-items: center; gap: var(--v-sp-2); flex-wrap: wrap; }
.v-footer a, .v-footer-link { color: var(--v-muted); text-decoration: none; }
.v-footer a:hover, .v-footer-link:hover { color: var(--v-green); text-decoration: underline; }
/* El botón de Vity se ve igual que los enlaces vecinos: es la misma clase de
   acción y distinguirlo sólo obligaría a mirar dos veces. */
.v-footer-link { background: none; border: none; padding: 0; font: inherit; cursor: pointer; }
.v-footer-sep { color: var(--v-muted-2); }
.v-footer-meta { font-variant-numeric: tabular-nums; }

@media (max-width: 680px) {
  /* Apilado y centrado: en un teléfono las tres piezas en fila se parten en
     lugares arbitrarios y el pie termina ocupando media pantalla. */
  .v-footer-inner { flex-direction: column; text-align: center; gap: var(--v-sp-2); }
}

/* ── Catálogo de canje ───────────────────────────────────────────────────────
 *
 * La vidriera donde los puntos dejan de ser un marcador. Vive acá y no en
 * `admin.css` porque es una pantalla del colaborador, hermana de Logros y
 * retos, y reusa su misma tarjeta oscura de encabezado.
 */

/* Tarjeta de saldo: misma familia visual que `.v-level`, porque contesta la
   pregunta gemela —cuánto tengo para gastar, contra cuánto llevo ganado—. */
.v-saldo { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; margin-bottom: 26px; }
.v-saldo-emoji { font-size: 56px; flex: 0 0 auto; }
.v-saldo-label {
  font-family: 'Archivo', sans-serif; font-size: 12px; color: var(--v-muted);
  font-weight: 700; text-transform: uppercase; letter-spacing: .14em;
}
.v-saldo-pts {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 42px;
  line-height: 1; margin: 6px 0 8px; letter-spacing: -1px;
}
.v-saldo-pts small { font-size: 20px; color: var(--v-muted); letter-spacing: 0; }
.v-saldo-nota { max-width: 46ch; }
.v-saldo-link { margin-left: auto; }

/* Cada premio es una tarjeta en columna: la acción siempre al pie, a la misma
   altura en todas, para que la fila se pueda recorrer sin saltar la vista. */
.v-premio-tile { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; }
.v-premio-tile > form { margin-top: auto; width: 100%; }
.v-premio-img { border-radius: var(--v-radius-sm); object-fit: cover; }
.v-premio-cat {
  font-size: 11px; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--v-muted);
}
.v-premio-tile-name { font-weight: 700; color: var(--v-ink); }
.v-premio-tile-desc { font-size: 13px; color: var(--v-ink-2); margin: 0; }
.v-premio-tile-costo {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 24px;
  color: var(--v-green); line-height: 1;
}
.v-premio-tile-costo small { font-size: 13px; color: var(--v-muted); }
.v-premio-btn { width: 100%; }
.v-premio-stock { font-size: 12px; color: var(--v-warn-fg); font-weight: 700; }

/*
 * El premio que no alcanza se apaga por HIJOS y no como bloque.
 *
 * Mismo motivo que `.v-badge-tile.is-locked`: `opacity` en el padre crea un
 * contexto de composición y arrastra a todo lo que tiene adentro sin excepción
 * posible. Acá eso dejaría al 50 % justamente el texto que dice cuántos puntos
 * faltan, que es lo ÚNICO que esa tarjeta vino a comunicar. El costo y el
 * nombre se atenúan; la meta, no.
 */
.v-premio-tile.is-locked .v-premio-img,
.v-premio-tile.is-locked .v-emoji,
.v-premio-tile.is-locked .v-premio-cat,
.v-premio-tile.is-locked .v-premio-tile-name,
.v-premio-tile.is-locked .v-premio-tile-desc,
.v-premio-tile.is-locked .v-premio-tile-costo { opacity: .55; }

/* Lo que falta, y por qué no se puede: en verde de marca y no en rojo. Es una
   meta, no un error — la persona no hizo nada mal. */
.v-premio-falta { font-size: 13px; font-weight: 700; color: var(--v-green-2); margin-top: 6px; }
.v-premio-bloqueo {
  margin-top: auto; width: 100%; padding: 10px;
  border-radius: var(--v-radius-sm); background: var(--v-fill);
  font-size: 13px; font-weight: 700; color: var(--v-muted);
}

/* «Cancelado» a secas deja a la persona preguntándose si perdió los puntos. */
.v-premio-devuelto { font-size: 12px; color: var(--v-ok-fg); margin-top: 4px; }

/* La cifra de puntos se lee igual acá que en el ranking y en administración. */
.v-premio-costo { font-family: 'Archivo', sans-serif; font-weight: 800; color: var(--v-green); white-space: nowrap; }

@media (max-width: 680px) {
  /* El enlace a Logros deja de flotar a la derecha: apilado ocupa su línea. */
  .v-saldo-link { margin-left: 0; }
}

/* ── Logros como tablero ─────────────────────────────────────────────────── */
/* Primera fila: el estado a la izquierda y la acción a la derecha. El nivel
   pide más ancho porque lleva la barra de progreso; la tarjeta de canje es
   una columna estrecha y alta, que es la forma que la hace destacar al lado de
   una tarjeta ancha. */
.v-tablero-cabecera { grid-template-columns: 1.55fr 1fr; align-items: stretch; }
/* Dentro de la grilla el espacio lo pone el `gap`: el margen propio de
   `.v-level` dejaría las dos tarjetas de la fila con distinta altura. */
.v-tablero-cabecera > .v-level { margin-bottom: 0; }

/* El ranking en columnas. Se lee por filas —primero, segundo, tercero de
   izquierda a derecha—, así que el orden del documento sigue siendo el orden
   del ranking y no hace falta repartirlo del lado del servidor. */
.v-rank-grid { grid-template-columns: repeat(3, 1fr); gap: 10px; }

/* La puerta al catálogo desde Logros y retos. Es una tarjeta entera clickeable
   —no un enlace de texto— porque compite con el nivel y el ranking por la
   atención, y un renglón se pierde entre los dos. */
.v-canje-destacado {
  display: flex; flex-direction: column; align-items: flex-start;
  justify-content: center; gap: 6px;
  text-decoration: none; color: inherit;
  border-color: var(--v-green);
  transition: transform .18s ease, box-shadow .18s ease;
}
.v-canje-destacado-emoji { font-size: 42px; line-height: 1; }
.v-canje-destacado-title {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 21px;
  color: var(--v-ink); line-height: 1.15;
}
.v-canje-destacado-note { max-width: 34ch; }
.v-canje-destacado-cta {
  display: inline-flex; align-items: center; gap: 8px; margin-top: auto;
  padding-top: var(--v-sp-3);
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 14px;
  color: var(--v-green);
}
.v-canje-destacado-arrow { font-size: 20px; transition: transform .18s ease; }
.v-canje-destacado:hover, .v-canje-destacado:focus-visible {
  transform: translateY(-3px); box-shadow: var(--v-shadow-lg);
}
.v-canje-destacado:hover .v-canje-destacado-arrow { transform: translateX(4px); }

/*
 * El halo que late.
 *
 * El cliente pidió que la acción principal de la pantalla estuviera «más
 * visible y animada». La animación es un anillo que se expande y se desvanece:
 * la tarjeta NO se mueve de lugar ni cambia de tamaño, así que no arrastra la
 * vista de quien está leyendo el nivel de al lado, y `box-shadow` no dispara
 * recálculo de posiciones como lo haría animar `transform: scale` sobre un
 * elemento de una grilla.
 *
 * El ciclo es de 3,2 s y no de 1 s a propósito: algo que parpadea rápido en un
 * costado deja de leerse como una invitación y pasa a leerse como una alarma.
 */
@keyframes vCanjeHalo {
  0%   { box-shadow: 0 0 0 0 var(--v-halo-canje); }
  70%  { box-shadow: 0 0 0 14px rgba(20, 160, 122, 0); }
  100% { box-shadow: 0 0 0 0 rgba(20, 160, 122, 0); }
}
.v-canje-destacado { animation: vCanjeHalo 3.2s ease-out infinite; }
/* Al pasar el cursor manda la sombra del hover: dos sombras compitiendo en el
   mismo elemento se pisan y el halo se ve cortado. */
.v-canje-destacado:hover, .v-canje-destacado:focus-visible { animation: none; }

/* `prefers-reduced-motion` no es una preferencia estética: hay gente a la que
   el movimiento en pantalla le produce mareo o migraña. Se apaga el latido y
   también el desplazamiento del hover; la tarjeta sigue destacándose por el
   borde verde, el tamaño y la sombra, que no se mueven. */
@media (prefers-reduced-motion: reduce) {
  .v-canje-destacado { animation: none; transition: none; }
  .v-canje-destacado:hover, .v-canje-destacado:focus-visible { transform: none; }
  .v-canje-destacado-arrow { transition: none; }
  .v-canje-destacado:hover .v-canje-destacado-arrow { transform: none; }
}

/* El tablero se angosta antes que el resto: la tarjeta de canje necesita ancho
   para que el texto no se parta en cuatro renglones, y el ranking en tres
   columnas deja de ser legible bastante antes de llegar al celular. */
@media (max-width: 1180px) {
  .v-rank-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 960px) {
  .v-tablero-cabecera { grid-template-columns: 1fr; }
  .v-canje-destacado-note { max-width: none; }
}

/* ══ Ayuda y soporte ═══════════════════════════════════════════════════════
   Tres reglas y ninguna paleta nueva: la pantalla se apoya entera en
   `v-card v-account-section`, `v-field` y `v-badge`, que es la misma gramática
   de Mi cuenta. Lo único que hace falta agregar es la altura del relato y la
   lista de pedidos propios. */

/* Un renglón alcanza para el asunto y no para contar qué pasó: si el campo del
   relato se ve chico, la gente escribe «no anda» y el ticket arranca con una
   pregunta. */
.v-soporte-relato { min-height: 132px; resize: vertical; line-height: 1.5; font-family: inherit; }

.v-soporte-lista { list-style: none; margin: 0; padding: 0; }
.v-soporte-item { padding: var(--v-sp-3) 0; border-top: 1px solid var(--v-border); }
.v-soporte-item:first-child { border-top: none; padding-top: 0; }

/* El estado va al extremo opuesto del asunto: es lo único que esta pantalla
   puede prometer —no hay notificación por correo— y tiene que leerse de un
   vistazo desde el pasillo de una tienda. Con `wrap`, en celular baja solo. */
.v-soporte-item-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--v-sp-2); flex-wrap: wrap; margin-bottom: 4px;
}

/* ══ Política de tratamiento de datos ══════════════════════════════════════
   Segunda pantalla pública de la plataforma, después del verificador de
   diplomas, y con una necesidad que ninguna otra tiene: es un documento LARGO
   que alguien va a leer entero al menos una vez. Por eso una columna de texto
   con ancho de lectura y no el ancho de la ventana — una línea de 180
   caracteres se abandona en el tercer renglón. */
.v-legal-shell { background: var(--v-bg); }
.v-legal { max-width: 74ch; margin: 0 auto; padding: var(--v-sp-6) var(--v-sp-4) 64px; }
.v-legal-head { text-align: center; margin-bottom: var(--v-sp-6); }
.v-legal-head img { margin-bottom: var(--v-sp-3); }
.v-legal-head .v-h1 { margin-bottom: var(--v-sp-2); }

/* ⚠️ El aviso de borrador. Es lo más importante de la pantalla y tiene que
   verse ANTES que el índice, sin desplazar y sin confundirse con el contenido.
   Va en el amarillo de advertencia del sistema y no en el rojo de error: no es
   que algo salió mal, es que esto todavía no rige. */
.v-legal-borrador {
  border: 2px solid var(--v-warn-solid); border-radius: var(--v-radius);
  background: var(--v-warn-bg); color: var(--v-warn-fg);
  padding: var(--v-sp-4); margin-bottom: var(--v-sp-6);
}
.v-legal-borrador p { margin: 0 0 var(--v-sp-2); line-height: 1.55; }
.v-legal-borrador p:last-child { margin-bottom: 0; }
.v-legal-borrador-titulo {
  font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 16px;
  letter-spacing: .04em;
}

.v-legal-indice {
  background: var(--v-surface); border: 1px solid var(--v-border);
  border-radius: var(--v-radius); padding: var(--v-sp-4); margin-bottom: var(--v-sp-6);
}
.v-legal-indice ol { margin: var(--v-sp-3) 0 0; padding-left: 20px; }
.v-legal-indice li { margin-bottom: 6px; }
.v-legal-indice a { color: var(--v-green-3); }

.v-legal-seccion { margin-bottom: var(--v-sp-6); }
.v-legal-seccion .v-h2 { margin-bottom: var(--v-sp-3); }
.v-legal-seccion .v-h3 { margin: var(--v-sp-4) 0 var(--v-sp-2); }
.v-legal-seccion p, .v-legal-seccion li { line-height: 1.6; color: var(--v-ink); }
.v-legal-seccion ul { padding-left: 20px; }
.v-legal-seccion li { margin-bottom: 6px; }

/* Las tablas del documento: comparan responsable contra encargado, dato contra
   finalidad y familia contra plazo. Con `scroll` para que en celular la tabla
   se desplace sola en vez de romper el ancho de lectura de todo el texto. */
.v-legal-tabla {
  width: 100%; border-collapse: collapse; margin: var(--v-sp-3) 0;
  font-size: 14px; display: block; overflow-x: auto;
}
.v-legal-tabla th, .v-legal-tabla td {
  border: 1px solid var(--v-border); padding: 8px 10px; text-align: left; vertical-align: top;
}
.v-legal-tabla th { background: var(--v-fill); font-weight: 700; }
.v-legal-meses { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; }

/* Lo que falta completar, marcado y no disimulado: un aviso de privacidad con
   los datos de contacto inventados le da al titular un canal que no existe. */
.v-legal-pendiente {
  color: var(--v-danger-fg); background: var(--v-danger-bg);
  font-weight: 700; letter-spacing: .03em;
}

.v-legal-nota {
  background: var(--v-fill); border-left: 3px solid var(--v-muted-2);
  padding: var(--v-sp-3); border-radius: var(--v-radius-sm); margin: var(--v-sp-3) 0;
  font-size: 14px; color: var(--v-ink-2);
}

/* El canal para ejercer los derechos, destacado en verde: es lo ÚNICO
   accionable de todo el documento, y tiene que encontrarse sin leerlo entero. */
.v-legal-canal {
  background: var(--v-fill-3); border: 1px solid var(--v-green);
  border-radius: var(--v-radius); padding: var(--v-sp-4); margin-top: var(--v-sp-3);
}
.v-legal-canal a { color: var(--v-green-3); word-break: break-all; }

.v-legal-estado-vity {
  background: var(--v-info-bg); color: var(--v-info-fg);
  border-radius: var(--v-radius-sm); padding: var(--v-sp-3);
}

.v-legal-pie {
  border-top: 1px solid var(--v-border); padding-top: var(--v-sp-4);
  font-size: 13px; color: var(--v-muted); text-align: center;
}
.v-legal-pie a { color: var(--v-green-3); }
.v-legal-borrador-recordatorio { color: var(--v-warn-fg); font-weight: 700; }

/* El logotipo de la instalación en la cabecera del documento legal: alto fijo,
   ancho libre. Cada cliente trae su marca con otra proporción, y una caja
   cuadrada le deformaría el suyo a la mitad de ellos. */
.v-legal-logo { height: 72px; width: auto; object-fit: contain; }
