/* ─────────────────────────────────────────────────────────────────────
   IN Design System — CSS canónico del portal INfinito (Comunidad IN).
   GENERADO: copia verbatim de web/app/globals.css. No editar aquí.
   Fuente de verdad: web/app/globals.css · doc: /api/design-system
   Uso externo: importa este fichero y usa los tokens var(--in-*) y las
   clases .in-* (botones .in-btn-*, .in-card, .in-input, .in-badge…).
   Tema claro/oscuro incluido: el bloque :root define claro y
   [data-theme="dark"] / prefers-color-scheme el oscuro.
   ───────────────────────────────────────────────────────────────────── */
@import "tailwindcss";


/* ── Sistema de Diseño INfinito — Opción C — Brand Guide Inversores IN ──
   Fuente canónica: docs/design-system.md v3.8
   v3.0 (paleta navy 'Opción C'): PLAN-20260515-ds-opcion-c.md
   v3.1 (tokens semánticos de estado/interacción + auditoría WCAG):
     PRD-20260602-contraste-sistema-diseno.md
     PLAN-20260602-contraste-sistema-diseno.md
     AUDIT-20260602-contraste-wcag.md
   v3.3 (contraste alto: superficies, bordes y jerarquía de texto):
     PRD-20260707-contraste-ds-infinito.md
     PLAN-20260707-contraste-ds-infinito.md
     Spec visual: web/public/mockups/PRD-20260707-contraste-ds-infinito/v2.html
   v3.8 (2026-08-18, petición de la comunidad: «el modo oscuro, más oscuro»):
     toda la escalera de superficies OSCURAS baja de luminancia manteniendo
     el orden bg < surface-deep < surface < card y los deltas entre peldaños
     (las cards siguen despegándose del fondo). Los velos radiales del body
     bajan de alpha (0.20→0.13 navy, 0.08→0.05 rojo) porque eran lo que más
     aclaraba la página. El tema CLARO no se toca. El contraste solo mejora:
     todo el texto gana ratio (verificado con scripts/audits/contrast.py).

   Paleta semántica (usar siempre via var(--in-*), nunca hardcode):
   --in-bg            Fondo de página         #020610  (navy casi negro)
   --in-bg-mid        Fondo secciones/hero    #040C18
   --in-surface       Superficie cards        #0A1526
   --in-surface-deep  Cards secundarias       #060C16
   --in-card          Card elevada            #0F2039
   --in-border        Borde estándar          rgba(255,255,255,0.16)
   --in-border-bright Borde destacado/hover   rgba(255,255,255,0.30)
   --in-accent        Azul corporativo IN     #003F72  (Pantone 7693C)
   --in-accent-hover  Hover acento            #004f8f
   --in-accent-glow   Glow acento             rgba(0,63,114,0.4)
   --in-danger        Rojo acento IN          #E65558  (Pantone 710C)
   --in-danger-hover  Hover rojo              #c94448
   --in-danger-glow   Glow rojo               rgba(230,85,88,0.35)
   --in-success       Verde estado OK         #6EE7B7
   --in-success-soft  Verde texto             #34D399
   --in-warning       Ámbar estado aviso      #FBBF24
   --in-warning-soft  Ámbar texto             #FCD34D
   --in-incierto       Naranja Claude (marca MCP/Claude)   #E0613C
   --in-incierto-text  Naranja claro texto sobre navy      #F0A98E
   --in-incierto-soft  Fondo tenue sección INcierto        rgba(224,97,60,0.10)
   --in-incierto-border Borde destacado sección INcierto   rgba(224,97,60,0.55)
   --in-text          Texto principal         #FFFFFF
   --in-text-soft     Texto secundario        #E0EAF6
   --in-text-muted    Texto atenuado          #B0C6E0
   --in-text-subtle   Texto sutil/captions    #9BB6D4
   --in-input-bg      Pozo del campo (input)  #03080F
   --in-card-head-bg  Franja cabecera card    rgba(255,255,255,0.06)
   --in-card-head-border Cierre de cabecera   rgba(255,255,255,0.20)

   Tokens semánticos de interacción (v3.1):
   --in-link            Link / texto destacado    #6FB3E8  (ratio ≥7.5:1 sobre navy)
   --in-link-hover      Hover de link             #9CCAF0
   --in-active-text     Texto en estado activo    #FFFFFF  (= --in-text)
   --in-active-bg       Fondo de item activo      rgba(0,79,143,0.35)
   --in-hover-bg        Fondo hover items         rgba(255,255,255,0.05)
   --in-focus-ring      Outline focus accesible   rgba(108,179,232,0.6)

   REGLA DURA: --in-accent y --in-accent-hover NUNCA como color de texto.
   Composición azul-sobre-navy da ratio <2:1 (FAIL incluso para texto grande).
   Para link/texto destacado interactivo: usar --in-link.
   ──────────────────────────────────────────────────────────────────── */

:root {
  /* Ancho del "shell" del Portal del miembro (PLAN-20260706) — una sola fuente
     de verdad para que el header y el contenido de /portal/home y de todas sus
     secciones (Mis datos, Mi perfil inversor, Mi CV, Escanear) midan y se
     justifiquen igual en móvil y en laptop. Mismos breakpoints que ya usaba
     /portal/home (430px móvil → 680px desktop desde 760px, PRD-20260625). */
  --portal-shell-w: 430px;

  /* Fondos — navy profundo (brand guide Inversores IN)
     v3.3 (PLAN-20260707): surface/card suben de luminancia para que el
     contenedor se despegue del fondo. Escalera: bg < surface-deep < surface < card. */
  --in-bg:            #020610;
  --in-bg-mid:        #040C18;
  --in-surface:       #0A1526;
  --in-surface-deep:  #060C16;
  --in-card:          #0F2039;
  --in-overlay:       rgba(1,3,8,.90);   /* scrim de modales/lightbox (oscuro) */
  /* Fondo del visor de fotos a pantalla completa: casi negro en LOS DOS temas
     (como la galería del móvil). El velo de modales en claro deja ver la página
     de detrás y la foto pierde protagonismo (Mark, 2026-10-01). */
  --in-visor-bg:      rgba(2,4,9,.97);
  /* Miniatura de mapa (tarjeta de dirección): los tiles de OSM son claros, así
     que en tema oscuro se atenúan para que no deslumbren dentro de la ficha.
     --in-overlay-chip: pastilla sobre la imagen (el ↗ de «ver en el mapa»). */
  --in-map-filter:    saturate(.85) brightness(.88) contrast(1.02);
  --in-overlay-chip:  rgba(2, 6, 16, .78);
  --in-overlay-chip-text: #FFFFFF;  /* la pastilla es oscura en ambos temas */
  /* Burbuja "propia" del chat de notas 360 (equipo, mensajes enviados) */
  --in-bubble-me:        #0D2C4A;
  --in-bubble-me-border: rgba(111, 179, 232, 0.28);

  /* Chat de notas 360 (PRD-20260714) — avatares de fuente: círculo SÓLIDO de color
     con el icono en blanco; el nombre del contacto va del MISMO tono (tinta -ink,
     legible sobre la superficie del tema). Colores del mockup avatares-fuentes. */
  --in-on-solid:          #FFFFFF;   /* icono/iniciales sobre relleno sólido (siempre blanco) */
  --in-src-hotmart:       #F04E23;   --in-src-hotmart-ink:  #F27A5F;
  --in-src-facturas:      #16A34A;   --in-src-facturas-ink: #34D399;
  --in-src-zooms:         #2D8CFF;   --in-src-zooms-ink:    #6FB3E8;
  --in-src-eventos:       #8B5CF6;   --in-src-eventos-ink:  #A78BFA;
  --in-src-luxora:        #DB2777;   --in-src-luxora-ink:   #F06FA8;
  --in-src-discord:       #5865F2;   --in-src-discord-ink:  #8891F2;
  /* Canal WhatsApp en el Histórico (verde de marca, icono blanco encima) */
  --in-src-whatsapp:      #25D366;   --in-src-whatsapp-ink: #4ADE80;
  /* Avatares de persona (fill sólido con iniciales blancas; el nombre va del mismo color) */
  --in-av-1:#2563EB; --in-av-2:#059669; --in-av-3:#EA580C; --in-av-4:#7C3AED; --in-av-5:#0891B2; --in-av-6:#DB2777;

  /* Bordes — visibles sobre navy (v3.3: 0.07→0.16 y 0.15→0.30) */
  --in-border:        rgba(255, 255, 255, 0.16);
  --in-border-bright: rgba(255, 255, 255, 0.30);

  /* Acento principal — azul corporativo Pantone 7693C */
  --in-accent:        #003F72;
  --in-accent-hover:  #004f8f;
  --in-accent-glow:   rgba(0, 63, 114, 0.4);

  /* Acento secundario — rojo Pantone 710C */
  --in-danger:        #E65558;
  --in-danger-hover:  #c94448;
  --in-danger-glow:   rgba(230, 85, 88, 0.35);

  /* Rojo de MARCA actual de Inversores IN (paleta vigente que manda José,
     2026-07-14): rojo Pantone 192 C. Es un rojo de MARCA/gráfico (logotipo),
     NO el rojo semántico de peligro/estado —por eso es un token propio y no
     toca --in-danger. Índigo Pantone 2685 C reservado para cuando se migre la
     paleta completa del Portal. Solo lo usa hoy el logotipo "Portal IN". */
  --in-brand-red:     #E4003F;   /* Pantone 192 C  · RGB 228 0 63  */
  --in-brand-red-ink: #FFFFFF;   /* texto sobre el bloque rojo     */
  --in-brand-indigo:  #1C0A66;   /* Pantone 2685 C · RGB 28 10 102 */

  /* Semánticos auxiliares — estados de verificación / fiabilidad
     (tonos sobrios sobre fondo navy, no compiten con el acento azul corporativo) */
  --in-success:       #6EE7B7;  /* verde menta, estado OK */
  --in-success-soft:  #34D399;  /* verde para texto sobre superficies oscuras */
  --in-warning:       #FBBF24;  /* ámbar, estado indeterminado/aviso */
  --in-warning-soft:  #FCD34D;  /* ámbar suave para texto */

  /* Acento sección "Acceso INcierto vía MCP" — terracota (marca Claude),
     distingue la sección del resto de cards navy sin competir con el acento
     azul corporativo. Solo para esa card. */
  --in-incierto:        #E0613C;             /* naranja Claude, intenso */
  --in-incierto-text:   #F0A98E;             /* naranja claro para título sobre navy */
  --in-incierto-soft:   rgba(224, 97, 60, 0.10);  /* fondo tenue de la card */
  --in-incierto-border: rgba(224, 97, 60, 0.55);  /* borde destacado */

  /* cal.com — sección "Reservas de cita" (PRD-20260624). Reutiliza el azul --in-link. */
  --in-calcom-soft:     rgba(111, 179, 232, 0.08);  /* fondo tenue de la card */
  --in-calcom-border:   rgba(111, 179, 232, 0.45);  /* borde destacado */

  /* Texto (jerarquía descendente) — v3.3: los 3 niveles inferiores suben
     de luminancia (subtle pasa de 3.9:1 a ~8:1) preservando text > soft > muted > subtle */
  --in-text:          #FFFFFF;
  --in-text-soft:     #E0EAF6;
  --in-text-muted:    #B0C6E0;
  --in-text-subtle:   #9BB6D4;
  --in-logo-ink:      #FFFFFF;   /* "PORTAL" del logo: blanco sobre el navy oscuro del Portal */

  /* ── Contenedor con cabecera propia (v3.3, PLAN-20260707) ─────────────
     Pozo del campo + franja de cabecera del contenedor (mockup v2). */
  --in-input-bg:        #03080F;
  --in-card-head-bg:    rgba(255, 255, 255, 0.06);
  --in-card-head-border: rgba(255, 255, 255, 0.20);

  /* ── Tokens semánticos de interacción (v3.1, PRD-20260602) ────────────
     Separan el ROL del color del VALOR cromático. El acento --in-accent
     se reserva como fondo/borde; el texto destacado interactivo usa
     --in-link (luminancia suficiente para AA sobre navy).
     Ver docs/design-system.md §1.7 y docs/audits/AUDIT-20260602-*.md */

  /* Links y texto destacado interactivo — ratio ≥7.5:1 sobre navy */
  --in-link:          #6FB3E8;
  --in-link-hover:    #9CCAF0;

  /* Estado activo (nav, dropdown, tabs, items de lista) */
  --in-active-text:   #FFFFFF;
  --in-active-bg:     rgba(0, 79, 143, 0.35);

  /* Hover de items no activos — sutil, no compite con el activo */
  --in-hover-bg:      rgba(255, 255, 255, 0.05);

  /* Focus visible accesible (WCAG SC 2.4.7) */
  --in-focus-ring:    rgba(108, 179, 232, 0.6);

  /* ── Tokens semánticos de ESTADO y VALOR (v3.2) ───────────────────────
     Cierran el drift de colores de estado hardcodeados por componente.
     Verde y ámbar ya son legibles como texto (--in-success 11.4:1,
     --in-warning-soft 12:1 sobre navy); aquí se añade el rojo-texto, los
     rellenos suaves de cajas de alerta y el par positivo/negativo de valor.
     Ver docs/design-system.md §1.8. Ratios verificados con scripts/audits/contrast.py */

  /* Texto y relleno de estado (éxito / aviso / error) sobre navy */
  --in-danger-text:   #ff8099;                  /* rojo claro texto error — 7.3:1 ✅ */
  --in-red-text:      #E65558;                  /* rojo de marca como TEXTO (5.4:1 sobre navy) */
  --in-danger-bg:     rgba(230, 85, 88, 0.10);  /* relleno caja error (rojo marca) */
  --in-warning-bg:    rgba(251, 191, 36, 0.10); /* relleno caja aviso */
  --in-success-bg:    rgba(110, 231, 183, 0.10);/* relleno caja OK */

  /* «Océano azul» — 4º tramo del semáforo INcierto, por encima del verde
     (oportunidad excepcional). Azul cielo, NO el navy de marca: --in-accent es
     casi invisible sobre fondo oscuro y se confundiría con --in-link. 9.8:1 ✅ */
  --in-ocean:         #7DD3FC;
  --in-ocean-bg:      rgba(125, 211, 252, 0.10);

  /* Valor positivo/negativo — KPIs (margen, capital, verificado, gratis).
     Semántica de MAGNITUD, distinta de estado OK/error. */
  --in-positive:      #4ade80;  /* verde valor+ — 10:1 ✅ */
  --in-positive-strong: #15803D; /* verde de botón de acción — blanco AA en ambos temas (4.5:1 claro, 5.9:1 oscuro) */
  --in-negative:      #f87171;  /* rojo valor−  — 6.3:1 ✅ */

  /* Avatar de icono sólido (listas de secciones de la ficha): relleno macizo con
     el icono en BLANCO. Los tonos válidos son los que dan ≥3:1 con blanco en los
     DOS temas — por eso aquí NO valen --in-positive (en oscuro es #4ade80, 1.8:1)
     ni --in-text-subtle (en oscuro es #9BB6D4, 2.0:1). Pizarra propia porque no
     había ningún neutro oscuro que sobreviviera al cambio de tema; valor único a
     propósito (mismo color en claro y en oscuro → contraste constante 7.3:1). */
  --in-avatar-slate:  #3E5871;

  /* Borde de elemento interactivo (input/botón) — SC 1.4.11 ≥3:1 (DT-180)
     v3.3: 0.35→0.65 — campo nítido incluso con brillo bajo */
  --in-border-interactive: rgba(255, 255, 255, 0.65);

  /* Tipografías — Montserrat display + Inter body */
  --in-font-display:  'Montserrat', ui-sans-serif, sans-serif;
  --in-font-body:     'Inter', ui-sans-serif, sans-serif;

  /* Texto SOBRE el acento (botón primario, chip activo, avatar de acento).
     Siempre fue blanco fijo porque el acento es navy en los dos temas; un
     skin con acento claro (LoVivimos: amarillo) necesita tinta oscura encima,
     así que el par vive en un token y no en cada clase (PRD-20261012). */
  --in-on-accent:     #FFFFFF;
  /* …y sus derivados para lo que se dibuja ENCIMA de una superficie de acento
     (las cards de FINA): un borde y un relleno tenues del mismo color que el
     texto, en vez de blancos alfa escritos a mano. */
  --in-on-accent-border: rgba(255, 255, 255, 0.40);
  --in-on-accent-soft:   rgba(255, 255, 255, 0.16);

  /* Alturas de línea canónicas (escala tipográfica v3.2) */
  --in-leading-tight:   1.25;  /* headings / cifras grandes */
  --in-leading-normal:  1.5;   /* UI / labels */
  --in-leading-relaxed: 1.6;   /* body copy (= line-height del body) */

  /* Radios */
  --in-radius-sm:     6px;
  --in-radius-md:     10px;
  --in-radius-lg:     16px;
  --in-radius-xl:     20px;
  --in-radius-pill:   999px;

  /* Escala de espaciado (AUDIT-20260812 §5.1 — base 4, tema-independiente).
     Regla: los componentes DS usan estos tokens; nada de `padding: 13px` a mano. */
  --in-space-1:  4px;
  --in-space-2:  8px;
  --in-space-3:  12px;
  --in-space-4:  16px;
  --in-space-5:  20px;
  --in-space-6:  24px;
  --in-space-8:  32px;
  --in-space-10: 40px;
  --in-space-12: 48px;
  --in-space-16: 64px;

  /* Motion (AUDIT-20260812) — nunca `ease`/`linear` en componentes DS */
  --in-duration-fast:   100ms;
  --in-duration-normal: 200ms;
  --in-duration-slow:   350ms;
  --in-ease-out:    cubic-bezier(0, 0, 0.2, 1);
  --in-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --in-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* solo feedback táctil */

  /* Iconografía — color por defecto (lucide, línea, stroke 1.8; nunca emoji) */
  --in-icon-color: var(--in-text-muted);

  /* Sombras */
  --in-shadow-card:   0 4px 24px rgba(0, 0, 0, 0.5);
  --in-shadow-glow:   0 0 32px rgba(0, 63, 114, 0.25);
  /* Escala de elevación (AUDIT-20260812): 1=card (alias) · 2=dropdown/panel · 3=sheet/modal.
     En oscuro la profundidad la da también el cambio de superficie, no solo la sombra. */
  --in-shadow-1: var(--in-shadow-card);
  --in-shadow-2: 0 8px 28px rgba(0, 0, 0, 0.55);
  --in-shadow-3: 0 16px 48px rgba(0, 0, 0, 0.6);

  /* Error de formulario (AUDIT-20260812) — pareja canónica para aria-invalid */
  --in-input-error-border: var(--in-danger);
  --in-input-error-ring:   var(--in-danger-glow);

  /* Ghost numbers (Opción C) */
  --in-ghost-color:   rgba(255, 255, 255, 0.04);
  --in-ghost-hover:   rgba(230, 85, 88, 0.12);

  /* ── Tinta de chips de rol/familia (lib/miembro-card-utils.getRoleStyle) ──
     El hue de cada familia se mantiene entre temas via bg/border con alpha;
     la TINTA del texto cambia por tema para garantizar contraste (los
     pasteles de dark eran ilegibles sobre fondo claro — fix 2026-08-10). */
  --in-role-embajador-ink: #FFD770;
  --in-role-mentor-ink:    #C4B5FD;
  --in-role-consultor-ink: #93C5FD;
  --in-role-master-ink:    #A5B4FC;
  --in-role-grado-ink:     #6EE7B7;
  --in-role-allin-ink:     #FCA974;
  --in-role-programa-ink:  #7DD3FC;
  --in-role-evento-ink:    #CBD5E1;

  /* ── Portal FLAT (rediseño flat 2026-07-14) ───────────────────────────
     Sistema plano y REUTILIZABLE para el Portal del miembro. Sustituye la
     profundidad (sombras / glows / gradientes) por jerarquía de borde 1px +
     fondo + espaciado + tipografía. La selección/activo se apoya en fondo
     azul tenue + borde azul; una ÚNICA sombra muy sutil se reserva a la
     pestaña activa. Centralizado aquí para que el acabado flat sea idéntico
     en todas las pantallas del portal, no solo en /portal/home.
     Radios definidos una sola vez (agnósticos de tema). */
  --in-flat-page-bg:       #050C17;                     /* fondo general (ligeramente elevado del bg) */
  --in-flat-surface:       #0A1526;                     /* superficie de card/sección */
  --in-flat-surface-alt:   #07101D;                     /* superficie atenuada (bloqueado / anidado) */
  --in-flat-border:        rgba(255, 255, 255, 0.14);   /* ÚNICO borde neutro */
  --in-flat-radius:        14px;                          /* radio consistente de cards/contenedores */
  --in-flat-radius-sm:     10px;                          /* radio consistente de controles/chips */
  --in-flat-active-bg:     rgba(10, 111, 194, 0.16);     /* fondo azul tenue de selección/activo */
  --in-flat-active-border: rgba(10, 111, 194, 0.55);     /* borde azul de selección/activo */
  --in-flat-active-shadow: 0 1px 3px rgba(0, 0, 0, 0.22);/* ÚNICA sombra sutil permitida (pestaña ON) */
}

/* ── Tema CLARO (PRD implícito 2026-07-08, mockup brand-center/v2-claro) ──
   Mismo sistema semántico, valores re-mapeados para fondo claro. El tema se
   activa con html[data-theme="light"] (script anti-flash en app/layout.tsx;
   preferencia en localStorage 'in-theme'; DEFAULT = light). Sin atributo (JS
   fallido) se cae al dark de :root — cero riesgo de regresión.
   Ratios AA verificados: texto #0B2A45/blanco 13.9:1 · subtle #5A768F 4.9:1 ·
   link #0A527F 7.2:1 · blanco sobre accent #06416A 10.6:1. */
html[data-theme="light"], .in-theme-light {
  color-scheme: light;

  --in-bg:            #EEF2F7;
  --in-bg-mid:        #F5F8FB;
  --in-surface:       #FFFFFF;
  --in-surface-deep:  #F3F6FA;
  --in-card:          #FFFFFF;
  --in-overlay:       rgba(15, 27, 45, 0.42);   /* scrim de modales/lightbox (claro) */
  --in-map-filter:    none;                     /* en tema claro los tiles van tal cual */
  --in-overlay-chip:  rgba(11, 42, 69, .72);
  --in-overlay-chip-text: #FFFFFF;
  --in-bubble-me:        #DCEBF7;
  --in-bubble-me-border: rgba(10, 82, 127, 0.30);
  /* Chat 360: el relleno del avatar se queda vivo (icono blanco encima), pero el
     NOMBRE necesita un tono más oscuro para contraste sobre superficies claras. */
  --in-src-hotmart-ink:  #C63A16;
  --in-src-facturas-ink: #0F7A37;
  --in-src-zooms-ink:    #1560B8;
  --in-src-eventos-ink:  #6D3FD4;
  --in-src-luxora-ink:   #B0175E;
  --in-src-discord-ink:  #4046B8;
  --in-src-whatsapp-ink: #128C7E;

  /* Tinta de chips de rol/familia — versión oscura del mismo hue, contraste
     AA sobre superficies claras (ver bloque homólogo en :root). */
  --in-role-embajador-ink: #8A6100;
  --in-role-mentor-ink:    #6D28D9;
  --in-role-consultor-ink: #1D4ED8;
  --in-role-master-ink:    #4338CA;
  --in-role-grado-ink:     #047857;
  --in-role-allin-ink:     #B45309;
  --in-role-programa-ink:  #0369A1;
  --in-role-evento-ink:    #475569;

  --in-border:        rgba(11, 42, 69, 0.14);
  --in-border-bright: rgba(11, 42, 69, 0.28);

  --in-accent:        #06416A;   /* Pantone 7693C exacto del manual */
  --in-accent-hover:  #0A527F;
  --in-accent-glow:   rgba(6, 65, 106, 0.22);

  --in-danger:        #E65558;
  --in-danger-hover:  #C94448;
  --in-danger-glow:   rgba(230, 85, 88, 0.22);

  --in-success:       #0E7A50;
  --in-success-soft:  #0B6B46;
  --in-warning:       #9A6C00;
  --in-warning-soft:  #8A6100;

  --in-incierto:        #C24E2C;
  --in-incierto-text:   #A03E20;
  --in-incierto-soft:   rgba(224, 97, 60, 0.08);
  --in-incierto-border: rgba(224, 97, 60, 0.45);

  --in-calcom-soft:     rgba(10, 82, 127, 0.06);
  --in-calcom-border:   rgba(10, 82, 127, 0.35);

  --in-text:          #0B2A45;
  --in-text-soft:     #2E4B66;
  --in-text-muted:    #3F5971;
  --in-text-subtle:   #455F78;
  --in-logo-ink:      #1C0A66;   /* "PORTAL" del logo: navy exacto del máster sobre fondo claro */

  --in-input-bg:        #FBFCFE;
  --in-card-head-bg:    rgba(11, 42, 69, 0.045);
  --in-card-head-border: rgba(11, 42, 69, 0.14);

  --in-link:          #0A527F;
  --in-link-hover:    #06416A;

  --in-active-text:   #06416A;
  --in-active-bg:     rgba(6, 65, 106, 0.12);
  --in-hover-bg:      rgba(11, 42, 69, 0.05);
  --in-focus-ring:    rgba(10, 82, 127, 0.5);

  --in-danger-text:   #B3373C;
  --in-red-text:      #B3373C;   /* rojo de marca usable como TEXTO en claro (5.3:1) */
  --in-danger-bg:     rgba(230, 85, 88, 0.08);
  --in-warning-bg:    rgba(154, 108, 0, 0.08);
  --in-success-bg:    rgba(14, 122, 80, 0.08);

  --in-ocean:         #0369A1;   /* océano azul en tema claro — 5.9:1 sobre card */
  --in-ocean-bg:      rgba(3, 105, 161, 0.08);

  --in-positive:      #15803D;
  --in-negative:      #B3373C;
  --in-avatar-slate:  #3E5871;   /* mismo valor que en oscuro: ver nota en :root */

  --in-border-interactive: rgba(11, 42, 69, 0.40);

  --in-shadow-card:   0 1px 2px rgba(11, 42, 69, 0.05), 0 10px 30px -12px rgba(11, 42, 69, 0.14);
  --in-shadow-glow:   0 0 32px rgba(6, 65, 106, 0.10);
  --in-shadow-2:      0 8px 28px rgba(11, 42, 69, 0.16);
  --in-shadow-3:      0 16px 48px rgba(11, 42, 69, 0.22);

  --in-ghost-color:   rgba(11, 42, 69, 0.05);
  --in-ghost-hover:   rgba(230, 85, 88, 0.10);

  /* Portal FLAT — contraparte clara (radios se heredan de :root) */
  --in-flat-page-bg:       #EDF1F6;
  --in-flat-surface:       #FFFFFF;
  --in-flat-surface-alt:   #F3F6FA;
  --in-flat-border:        rgba(11, 42, 69, 0.14);
  --in-flat-active-bg:     rgba(6, 65, 106, 0.08);
  --in-flat-active-border: rgba(6, 65, 106, 0.42);
  --in-flat-active-shadow: 0 1px 3px rgba(11, 42, 69, 0.10);

  /* Glass del header (portal) — contraparte clara */
  --in-glass-bg:      rgba(255, 255, 255, 0.78);
  --in-glass-chip:    rgba(255, 255, 255, 0.72);
  --in-glass-menu:    rgba(255, 255, 255, 0.95);
  --in-topbar-shadow: 0 1px 0 rgba(6,65,106,0.35), 0 2px 0 rgba(230,85,88,0.18), 0 4px 20px rgba(11,42,69,0.10);
  --in-sheet-shadow:  0 -8px 32px rgba(11, 42, 69, 0.16);
  --in-menu-shadow:   0 8px 32px rgba(11, 42, 69, 0.18);
}

/* Fondo de página claro: papel gris azulado + velos de los 2 colores de marca
   (mismo tratamiento que el mockup v2-claro — nada de blanco plano). */
html[data-theme="light"] body {
  background-color: var(--in-bg);
  background-image:
    radial-gradient(1100px 460px at 85% -180px, rgba(6, 65, 106, 0.10), transparent 62%),
    radial-gradient(800px 380px at -10% 8%, rgba(230, 85, 88, 0.05), transparent 55%);
}

/* Grain: en claro el blend overlay ensucia — casi imperceptible */
html[data-theme="light"] body::before { opacity: 0.012; mix-blend-mode: multiply; }

/* Botón rojo en claro: #E65558 con texto blanco se queda en 3.6:1 —
   el fondo baja a #C94448 (4.8:1) manteniendo el rojo de marca en bordes/tints */
html[data-theme="light"] .in-btn-danger, html[data-theme="light"] .in-btn-brand { background: #C94448; }
html[data-theme="light"] .in-btn-danger:hover:not(:disabled),
html[data-theme="light"] .in-btn-brand:hover:not(:disabled) { background: #B3373C; }

/* Checkbox nativo: pozo claro */
html[data-theme="light"] input[type="checkbox"] { background: #FFFFFF; }
html[data-theme="light"] input[type="checkbox"]:checked { background: var(--in-accent); }

/* ── Dark mode (default de :root) ──────────────────────────────────────── */
html {
  color-scheme: dark;
  /* Reserva el hueco de la barra de scroll aunque la página no la necesite:
     evita el salto lateral del layout al navegar entre vistas con y sin scroll */
  scrollbar-gutter: stable;

  /* Glass del header (portal) — valores oscuros históricos, tokenizados
     para que PortalHeader funcione en ambos temas */
  --in-glass-bg:      rgba(2, 6, 16, 0.78);
  --in-glass-chip:    rgba(8, 18, 34, 0.60);
  --in-glass-menu:    rgba(8, 18, 34, 0.94);
  --in-topbar-shadow: 0 1px 0 rgba(0,63,114,0.6), 0 2px 0 rgba(230,85,88,0.2), 0 4px 20px rgba(0,0,0,0.5);
  --in-sheet-shadow:  0 -8px 32px rgba(0, 0, 0, 0.7);
  --in-menu-shadow:   0 8px 32px rgba(0, 0, 0, 0.6);
}

body {
  background-color: var(--in-bg);
  background-image:
    radial-gradient(ellipse 1200px 800px at 15% 20%, rgba(0,63,114,0.13), transparent 60%),
    radial-gradient(ellipse 800px 600px at 85% 80%, rgba(230,85,88,0.05), transparent 55%);
  color: var(--in-text);
  font-family: var(--in-font-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: var(--in-leading-relaxed);
}

/* ── Grain overlay sutil — textura visual de profundidad ──────────────── */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0.025;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 240 240' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ── Scrollbar personalizada ──────────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--in-bg); }
::-webkit-scrollbar-thumb { background: var(--in-accent); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--in-border-bright); }

/* INdaga (morado, respuestas-discord) — texto AA en ambos temas */
:root { --in-indaga: #a78bfa; --in-indaga-contrast: #1a1030; --in-indaga-soft: rgba(167,139,250,0.12); --in-orange: #fb923c; --in-orange-soft: rgba(251,146,60,0.13); --in-orange-text: #FDBA74; }
html[data-theme="light"] { --in-indaga: #6D28D9; --in-indaga-contrast: #FFFFFF; --in-indaga-soft: rgba(109,40,217,0.10); --in-orange: #B45309; --in-orange-soft: rgba(180,83,9,0.10); --in-orange-text: #8A4A00; }

/* Texto gris de utilidades tailwind → token del DS (dashboard y sueltos) */
.text-zinc-500 { color: var(--in-text-subtle); }

/* ── Selección de texto ───────────────────────────────────────────────── */
/* Token canónico "seleccionado/activo" (§1.7). Translúcido → tiñe sobre
   cualquier superficie. Cierra la última fuga de morado v2.0 (DT-180). */
::selection { background: var(--in-active-bg); color: var(--in-text); }

/* ── Home: grid de cards responsive ──────────────────────────────────── */
.home-cards-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

@media (max-width: 639px) {
  .home-cards-grid { grid-template-columns: 1fr; }
}

/* ── CV Curriculum: padding lateral responsive ────────────────────────── */
.cv-content { padding: 28px 36px; }

@media (max-width: 639px) {
  .cv-content { padding: 10px 10px; }
}

/* ── CV: cabecera gestor responsive ───────────────────────────────────── */
.cv-header-card { padding: 20px; }

@media (max-width: 639px) {
  .cv-header-card { padding: 12px; gap: 10px; }
  /* avatar más pequeño en mobile para liberar espacio al nombre */
  .cv-header-card > div:first-child img {
    width: 60px !important;
    height: 60px !important;
  }
  .cv-header-card > div:first-child > div {
    width: 60px !important;
    height: 60px !important;
  }
  /* h1 nombre: tamaño más contenido en pantalla pequeña */
  .cv-header-card h1 { font-size: 17px !important; }
}

/* ── CV: secciones con padding interno responsive ─────────────────────── */
.cv-sobre-mi { padding: 20px; }

@media (max-width: 639px) {
  .cv-sobre-mi { padding: 14px 12px; }
}

/* ── Home dashboard ───────────────────────────────────────────────────── */
.home-wrapper {
  max-width: 960px;
  margin: 0 auto;
  padding: 28px 20px 48px;
}

.home-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 28px;
  flex-wrap: wrap;
  gap: 16px;
}

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 20px;
}

@media (max-width: 639px) {
  /* Margen lateral mnimo (8px) contra la ventana — el ancho extra lo
     gana el contenido dentro de cada card. */
  .home-wrapper { padding: 16px 8px 40px; }
  .home-header { flex-direction: column; gap: 12px; }
  .dashboard-grid { grid-template-columns: 1fr; gap: 14px; }
  .nav-user { display: none; }
}

/* ── Miembros: barra de búsqueda responsive ───────────────────────────
   En móvil, «Normalizar» y «Crear miembro» con texto aplastaban el buscador
   hasta dejarlo inutilizable. Bajo 640px los botones quedan solo con icono
   (el texto sigue en title/aria-label) y el buscador recupera el ancho. */
@media (max-width: 639px) {
  .miembros-toolbar-label { display: none; }
  .miembros-toolbar-btn { padding: 0 12px !important; gap: 0 !important; }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* PRD-20260531-refrescar-counts-en-buscar-duplicados: pulso suave para el
   indicador "Recalculando counts…" del modal de candidatos a fusionar. */
@keyframes in-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

/* Indicador de «estoy trabajando»: tres puntos que laten. Nace del copiloto de
   Mi camino inversor (Mark 2026-08-19): una espera de más de un minuto con un
   «Pensando…» quieto parecía la pantalla colgada. Va en el DS porque cualquier
   espera larga lo necesita, no solo esa. El color lo hereda del texto
   (`currentColor`), así que funciona igual en claro y en oscuro. */
.in-typing {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.in-typing i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  animation: in-typing-bounce 1.2s infinite ease-in-out;
}
.in-typing i:nth-child(2) { animation-delay: 0.18s; }
.in-typing i:nth-child(3) { animation-delay: 0.36s; }

@keyframes in-typing-bounce {
  0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-3px); }
}

/* Ecualizador de audio: barras que laten mientras suena una locución. Nace del
   tutorial por voz del portal (Mark 2026-09-08): sin una señal visual, quien
   tiene el volumen a cero no sabe que hay una voz explicando. El color lo
   hereda del texto (`currentColor`), como .in-typing, para valer en ambos
   temas. Con `data-quieto` (pausa) las barras se congelan y se atenúan. */
.in-eq {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: 16px;
}
.in-eq i {
  width: 3px;
  border-radius: 2px;
  background: currentColor;
  animation: in-eq-bar 0.9s infinite ease-in-out;
}
.in-eq i:nth-child(1) { animation-delay: 0s; }
.in-eq i:nth-child(2) { animation-delay: 0.25s; }
.in-eq i:nth-child(3) { animation-delay: 0.5s; }
.in-eq i:nth-child(4) { animation-delay: 0.15s; }
.in-eq[data-quieto] i {
  animation-play-state: paused;
  opacity: 0.35;
}

@keyframes in-eq-bar {
  0%, 100% { height: 5px; }
  50% { height: 16px; }
}

/* Quien pide menos movimiento sigue viendo señal de vida, pero sin saltos. */
@media (prefers-reduced-motion: reduce) {
  .in-typing i { animation: in-pulse 1.8s infinite ease-in-out; }
  .in-eq i { animation: in-pulse 1.8s infinite ease-in-out; height: 11px; }
}

/* ── Botones sistema de diseño IN ─────────────────────────────────────── */
/* El cursor va aquí, en la familia entera: cada clase solo aporta su par
   fondo/texto, así que un botón montado únicamente con `.in-btn-*` se quedaba
   sin la manita al pasar por encima (Mark 2026-08-19, botón «Finalizar» del
   perfil). Un `<button>` nativo no la trae de serie. */
.in-btn-primary, .in-btn-secondary, .in-btn-outline, .in-btn-ghost, .in-btn-danger, .in-btn-brand {
  cursor: pointer;
}
/* Maquetado de la familia (2026-10-10): icono + texto SIEMPRE en el mismo
   renglón y centrados. El preflight de Tailwind pone `svg { display: block }`,
   así que un lucide dentro de un botón o chip sin `inline-flex` se colocaba
   ENCIMA del texto y el control crecía a dos renglones (Mark: chips «Buscar por
   zona» del Estudio de zona en el móvil; antes, 2026-09-12, los botones del
   Modo Evento). Cada pantalla lo parcheaba a mano; ahora lo pone el DS y no
   hay que repetir `display: inline-flex` en ningún `<style jsx>`. */
.in-btn-primary, .in-btn-secondary, .in-btn-outline, .in-btn-ghost, .in-btn-danger, .in-btn-brand, .in-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.in-btn-primary > svg, .in-btn-secondary > svg, .in-btn-outline > svg, .in-btn-ghost > svg,
.in-btn-danger > svg, .in-btn-brand > svg, .in-chip > svg { flex: 0 0 auto; }
/* Tamaño por defecto de la familia (2026-11-03, Mark: tarjeta «Medidas del
   vídeo» de COTA con los botones sin forma). El preflight de Tailwind deja todo
   `<button>` con `padding: 0`, así que un `.in-btn-*` sin tamaño propio salía
   como un texto en una caja pegada. Ahora la clase de familia YA es un botón
   completo: 40 px de alto (toque mínimo de CHECKLIST-MAQUETA 4), radio 10,
   14 px. Una pantalla que quiera otro tamaño lo pisa como siempre (`.in-btn-sm`,
   su clase propia o el estilo en línea): esto es el suelo, no el techo. */
.in-btn-primary, .in-btn-secondary, .in-btn-outline, .in-btn-ghost, .in-btn-danger, .in-btn-brand {
  padding: 10px 16px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
}
.in-btn-primary:disabled, .in-btn-secondary:disabled, .in-btn-outline:disabled,
.in-btn-ghost:disabled, .in-btn-danger:disabled, .in-btn-brand:disabled {
  cursor: default;
  /* Un botón deshabilitado tiene que VERSE deshabilitado: hasta 2026-08-26 esta
     familia solo cambiaba el cursor, así que un `disabled` seguía pintado con el
     acento pleno y la gente lo pulsaba esperando que hiciera algo (Mark, sobre
     el «Crear tarea» de NEXO: «está enabled aunque pulsarlo no sirve para
     nada»). Mismo tratamiento que `.in-input:disabled`, que ya lo hacía bien. */
  opacity: 0.5;
  box-shadow: none;
}

.in-btn-primary {
  background: var(--in-accent);
  color: var(--in-on-accent);
  border: none;
}
.in-btn-primary:hover:not(:disabled) {
  background: var(--in-accent-hover);
  box-shadow: 0 0 16px var(--in-accent-glow);
}

.in-btn-secondary {
  background: var(--in-surface-deep);
  color: var(--in-text-soft);
  /* border-bright (no border): en modo claro --in-border (14%) es demasiado
     tenue y el botón queda "sin definir" sobre superficies claras. */
  border: 1px solid var(--in-border-bright);
}
.in-btn-secondary:hover:not(:disabled) {
  background: var(--in-card);
  border-color: var(--in-border-bright);
}

.in-btn-outline {
  background: transparent;
  color: var(--in-text-soft);
  border: 1px solid var(--in-border-bright);
}
.in-btn-outline:hover:not(:disabled) {
  background: var(--in-surface);
  color: var(--in-text);
}

.in-btn-ghost {
  background: transparent;
  color: var(--in-text-muted);
  border: none;
}
.in-btn-ghost:hover:not(:disabled) {
  background: var(--in-surface);
  color: var(--in-text-soft);
}

.in-btn-danger {
  /* Coral #C94448 (= --in-danger-hover) para que el texto blanco pase AA en
     AMBOS temas: blanco/#C94448 = 4.8:1 (el coral puro #E65558 daba 3.6:1).
     Arregla todos los botones de peligro, incl. "Quitar foto" del lightbox. */
  background: var(--in-danger-hover);
  color: #FFFFFF;
  border: none;
}
.in-btn-danger:hover:not(:disabled) {
  background: var(--in-danger-hover);
  box-shadow: 0 0 16px var(--in-danger-glow);
}

/* CTA en rojo de MARCA (Pantone 710C, el rojo del «IN» del logo): mismo par
   fondo/texto AA que .in-btn-danger, pero con semántica de identidad, no de
   peligro. Para la acción que tiene que destacar por encima del primario azul
   (p.ej. «Solicitar mi alta» en la ola de altas, Didac 2026-09-10). Úsalo
   como mucho una vez por pantalla: dos rojos ya no destacan. */
.in-btn-brand {
  background: var(--in-danger-hover);
  color: #FFFFFF;
  border: none;
}
.in-btn-brand:hover:not(:disabled) {
  background: var(--in-danger-hover);
  box-shadow: 0 0 16px var(--in-danger-glow);
}

/* ── Tarjeta de sección (navegación de nivel 1) ────────────────────────
   Las secciones de una pantalla, como tarjetas con su contador: se ve cuántos
   registros hay ANTES de entrar. Mark 2026-08-18.

   Jerarquía cromática contra la tarjeta-filtro (nivel 2, `.in-kpi-btn`):
     nivel 1 → fondo SÓLIDO (tinte navy en reposo, acento pleno al estar activa)
     nivel 2 → fondo de superficie (blanco en tema claro)
   Así se distingue de un vistazo "dónde estoy" de "qué parte estoy mirando".

   El par de la activa es el mismo de `.in-btn-primary` (acento + blanco), ya
   validado en ambos temas; el de reposo es superficie profunda + texto normal. */
.in-nav-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 100%;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid var(--in-border-bright);
  background: var(--in-surface-deep);
  color: var(--in-text);
  text-align: left;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.in-nav-card:hover:not([aria-selected="true"]) {
  background: var(--in-card);
  border-color: var(--in-accent);
}
.in-nav-card:focus-visible {
  outline: 2px solid var(--in-focus-ring);
  outline-offset: 2px;
}
.in-nav-card[aria-selected="true"] {
  background: var(--in-accent);
  border-color: var(--in-accent);
  color: var(--in-on-accent);          /* mismo par que .in-btn-primary */
  box-shadow: 0 0 18px var(--in-accent-glow);
}
.in-nav-card__titulo {
  font-size: 14px;
  font-weight: 650;
  line-height: 1.25;
}
.in-nav-card__valor {
  font-size: 26px;
  font-weight: 650;
  line-height: 1.1;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
/* Empuja la descripción al fondo: así los números de todas las tarjetas quedan
   a la misma altura aunque los textos ocupen distinto. */
.in-nav-card__pie {
  margin-top: auto;
  padding-top: 6px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--in-text-muted);
}
/* En la activa el pie hereda el blanco del par primario y solo baja de peso:
   fijar un rgba a mano aquí rompería el tema claro y al guardián del DS. */
.in-nav-card[aria-selected="true"] .in-nav-card__pie { color: inherit; opacity: .82; }

/* ── Tarjeta-filtro (KPI accionable) ───────────────────────────────────
   Segundo nivel de navegación: la pestaña dice DÓNDE estás y estas tarjetas
   parten esa cola en sus casos. Nacen en /admin/hotmart (Mark 2026-08-18): las
   métricas ya estaban ahí, pero parecían decoración — nadie veía que se podía
   pulsar para quedarse solo con "los que deben dinero".

   Estado seleccionado = borde de acento + fondo activo (nunca invertir el par
   fondo/texto: en claro el acento navy con texto suave no pasaría AA). */
.in-kpi-btn {
  display: block;
  width: 100%;
  text-align: left;
  padding: 13px 15px;
  border-radius: 12px;
  border: 1px solid var(--in-border);
  background: var(--in-surface);
  color: var(--in-text);
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.in-kpi-btn:hover:not(:disabled) {
  background: var(--in-hover-bg);
  border-color: var(--in-border-bright);
}
.in-kpi-btn:focus-visible {
  outline: 2px solid var(--in-focus-ring);
  outline-offset: 2px;
}
.in-kpi-btn[aria-pressed="true"] {
  border-color: var(--in-accent);
  background: var(--in-active-bg);
  box-shadow: inset 0 0 0 1px var(--in-accent);
}
/* Variante no pulsable: misma caja, pero se lee como dato, no como control. */
.in-kpi-btn--dato {
  cursor: default;
  border-style: dashed;
}
.in-kpi-btn__label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
  color: var(--in-text-muted);
}
.in-kpi-btn__value {
  margin-top: 2px;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
/* El galón que anuncia "esto abre un nivel más". */
.in-kpi-btn__caret {
  font-size: 11px;
  opacity: .55;
}
.in-kpi-btn[aria-pressed="true"] .in-kpi-btn__caret { opacity: 1; }

/* ── Botón de miembro IN (identidad accionable) ────────────────────────
   Pastilla que presenta a una persona COMO miembro IN: avatar + marca "IN"
   de la marca (rojo Pantone 192 C) + nombre, y al pulsarla se abre su ficha.
   Nace en /admin/hotmart (Mark 2026-08-18): un badge plano no comunicaba que
   detrás hay una ficha, y no se distinguía a simple vista quién está
   identificado como miembro y quién no.

   Contraste garantizado en AMBOS temas porque el par fondo/texto sale de
   tokens homólogos (--in-surface / --in-text-soft) y la marca roja usa su
   propio par de marca (--in-brand-red / --in-brand-red-ink). Nunca fijar
   color a mano aquí: rompería el modo claro. */
.in-miembro-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  max-width: 100%;
  /* Sin padding a la izquierda ni arriba/abajo: el avatar ocupa TODA la altura
     interior y su circunferencia coincide con el stroke del pill (Mark
     2026-08-19). Así la cara se ve un 23% mayor sin que el botón crezca. */
  padding: 0 7px 0 0;
  border-radius: 999px;
  border: 1px solid var(--in-border-bright);
  background: var(--in-surface);
  color: var(--in-text-soft);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.in-miembro-btn:hover:not(:disabled) {
  background: var(--in-hover-bg);
  border-color: var(--in-brand-red);
  color: var(--in-text);
}
.in-miembro-btn:focus-visible {
  outline: 2px solid var(--in-focus-ring);
  outline-offset: 2px;
}
/* Envoltorio del avatar: ancla la marca IN a su esquina. */
.in-miembro-btn__av {
  position: relative;
  display: inline-flex;
  flex: none;
}
/* La marca va al FINAL del botón, no sobre el avatar (Mark 2026-08-19):
   apoyada en la esquina de la foto tapaba justo la cara y costaba reconocer a
   quién estabas viendo, que es lo único que este control tiene que resolver. */
.in-miembro-btn__mark {
  flex: none;
  padding: 3px 5px;
  border-radius: 4px;
  background: var(--in-brand-red);
  color: var(--in-brand-red-ink);
  font-size: 9px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: .02em;
  font-family: var(--in-font-display);
}
.in-miembro-btn__nom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ── Versión GRANDE (Mark 2026-08-19) ──────────────────────────────────
   Para tarjetas y cabeceras, donde hay aire vertical: la foto asoma por
   arriba y por abajo del pill (máxima presencia de la persona) y la altura
   que gana el control se aprovecha para una segunda línea con la membresía
   más alta del miembro y su edición. La marca IN cierra esa segunda línea
   por la derecha, así el botón no se alarga por su culpa.
   NO usarla en tablas densas: la foto sobresale y engordaría cada fila. */
.in-miembro-btn--grande {
  height: 56px;
  gap: 12px;
  padding: 0 10px 0 0;
}
.in-miembro-btn--grande .in-miembro-btn__av { margin-left: -2px; }
.in-miembro-btn__txt {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  padding: 6px 0;
  text-align: left;
}
.in-miembro-btn--grande .in-miembro-btn__nom {
  font-size: 15px;
  font-weight: 700;
  color: var(--in-text);
}
/* Línea 2: membresía a la izquierda, marca IN pegada a la derecha. */
.in-miembro-btn__l2 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.in-miembro-btn__curso {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 500;
  color: var(--in-text-muted);
}
/* Control partido: el nombre abre la ficha y el galón despliega lo que se
   puede hacer CON ese vínculo (desconectarlo, conectar otro). Mark 2026-08-18:
   el miembro y sus acciones estaban en columnas distintas y no se leían como
   la misma cosa. El menú evita además que una acción destructiva viva a un clic
   de distancia del nombre. */
.in-miembro-wrap {
  position: relative;
  display: inline-flex;
  max-width: 100%;
}
.in-miembro-btn--split {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: none;
}
.in-miembro-caret {
  display: inline-flex;
  align-items: center;
  padding: 0 9px;
  border: 1px solid var(--in-border-bright);
  border-top-right-radius: 999px;
  border-bottom-right-radius: 999px;
  background: var(--in-surface);
  color: var(--in-text-muted);
  font-size: 11px;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.in-miembro-caret:hover,
.in-miembro-caret[aria-expanded="true"] {
  background: var(--in-hover-bg);
  border-color: var(--in-brand-red);
  color: var(--in-text);
}
/* Vive en <body> (portal desde MiembroINButton): las tablas de admin recortan
   con `overflow:auto` y las tarjetas con `overflow:hidden`, y el menú se
   quedaba a medias. La posición la calcula el componente; aquí solo el aspecto.
   z-index por encima de los modales de la casa (z-50 de Tailwind). */
.in-miembro-menu {
  position: fixed;
  z-index: 60;
  min-width: 210px;
  padding: 4px;
  border-radius: 10px;
  border: 1px solid var(--in-border-bright);
  background: var(--in-card);
  box-shadow: 0 12px 28px rgba(0, 0, 0, .28);
}
.in-miembro-menu__item {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--in-text-soft);
  font-size: 13px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}
.in-miembro-menu__item:hover:not(:disabled) { background: var(--in-hover-bg); color: var(--in-text); }
.in-miembro-menu__item:disabled { opacity: .5; cursor: default; }
.in-miembro-menu__item--peligro { color: var(--in-danger); }
.in-miembro-menu__item--peligro:hover:not(:disabled) { background: var(--in-danger-glow); color: var(--in-danger); }

/* Variante "aún no sabemos quién es": el hueco del miembro ES la acción de
   identificarlo, en vez de un texto muerto. */
.in-miembro-btn--vacio {
  padding: 6px 13px;
  border-style: dashed;
  border-color: var(--in-link);
  background: transparent;
  color: var(--in-link);
}
.in-miembro-btn--vacio:hover:not(:disabled) {
  background: var(--in-active-bg);
  border-color: var(--in-link);
  color: var(--in-link-hover);
}

/* ── Segmented control y chip de filtro (v3.5, PRD-20260728) ────────
   Selector exclusivo tipo pestañas y chips de filtro. El par activo calca
   .in-btn-primary (accent + blanco FIJO, AA en ambos temas: 10.75:1 oscuro,
   10.6:1 claro). NUNCA montar el estado activo a mano con tokens de texto:
   --in-text sobre --in-accent en tema claro es tinta sobre navy (<2:1). */
.in-segmented {
  display: flex;
  gap: 6px;
  background: var(--in-surface);
  border: 1px solid var(--in-border);
  border-radius: 999px;
  padding: 4px;
}
.in-segmented-btn {
  flex: 1;
  text-align: center;
  padding: 9px 6px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  background: transparent;
  color: var(--in-text-soft);
}
.in-segmented-btn:hover:not(.active):not(:disabled) { background: var(--in-hover-bg); }
.in-segmented-btn:focus-visible { outline: 2px solid var(--in-focus-ring); }
.in-segmented-btn.active {
  background: var(--in-accent);
  color: var(--in-on-accent);
}
/* Barra fija de pantalla (Biblia IN, José 26-oct): las pestañas y el submenú de una
   pantalla larga se quedan arriba al bajar, como en Máster IN. Debajo de la barra
   superior del shell (56 px). Uso: <div class="in-barra-fija"><div class="in-barra-fija__fila">
   <div class="in-segmented">…</div></div><div class="in-barra-fija__fila">chips…</div></div>.
   Las anclas de la pantalla llevan `scroll-margin-top: var(--in-barra-fija-alto)`. */
:root { --in-barra-fija-alto: 230px; }
.in-barra-fija {
  position: sticky;
  top: 56px;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0 0 14px;
  padding: 8px 0 10px;
  background: var(--in-bg);
  border-bottom: 1px solid var(--in-border);
}
.in-barra-fija__fila {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.in-barra-fija__fila::-webkit-scrollbar { display: none; }
.in-barra-fija__fila > * { flex-shrink: 0; }
.in-barra-fija .in-segmented-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  white-space: nowrap;
}

/* Botón compacto (v3.9): tamaño para acciones de fila (tabla, lista, ficha).
   Solo TAMAÑO; el color lo pone la clase de familia (`in-btn-outline`…).
   Antes cada pantalla lo escribía en línea y un botón que no admite estilo
   en línea (BotonWhatsApp con `clase`) no se podía igualar a sus vecinos. */
.in-btn-sm {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.in-btn-sm > svg { width: 14px; height: 14px; flex: 0 0 auto; }

/* Compacto: cabe en una celda de tabla o en una fila de ficha. No se estira
   (inline, sin flex:1) y mantiene el par activo blanco fijo sobre acento. */
/* Pestañas de sección que deben caber SIEMPRE en el ancho (Panel del Grado,
   Mark 2026-10-17: en móvil se cortaban y salía barra de scroll). Ocupan el
   ancho disponible hasta un tope; en móvil se reparten y sueltan el icono. */
.in-segmented--fluid {
  display: flex;
  width: 100%;
  max-width: 560px;
}
.in-segmented--fluid .in-segmented-btn {
  flex: 1 1 auto;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 14px;
  white-space: nowrap;
  text-decoration: none;
}
@media (max-width: 520px) {
  .in-segmented--fluid { gap: 2px; }
  .in-segmented--fluid .in-segmented-btn { padding: 8px 6px; font-size: 13px; }
  .in-segmented--fluid .in-segmented-btn svg { display: none; }
}
.in-segmented--sm {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
}
.in-segmented--sm .in-segmented-btn {
  flex: 0 0 auto;
  padding: 4px 10px;
  font-size: 12px;
}

.in-chip {
  font-size: 12px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid var(--in-border-interactive);
  background: var(--in-surface);
  color: var(--in-text-soft);
}
.in-chip:hover:not(.active):not(:disabled) { background: var(--in-hover-bg); }
.in-chip:focus-visible { outline: 2px solid var(--in-focus-ring); }
.in-chip.active {
  background: var(--in-accent);
  border-color: var(--in-accent);
  color: var(--in-on-accent);
}

/* ── Chip de atención (v3.6) ──────────────────────────────────────────
   Variante de .in-chip para lo que reclama una acción y se perdería
   entre chips neutros (p. ej. "6 propuestas · 6 sin revisar" junto a
   "Corte de vídeo"). El color va en el RELLENO y el BORDE; la etiqueta
   se queda en `--in-text`.
   Dos pares medidos y DESCARTADOS, no rehacerlos:
   · `--in-orange` como texto sobre `--in-orange-soft` = 4.38:1 en tema
     claro — falla AA para 12px/600 (no es "texto grande").
   · blanco sobre `--in-orange` sólido = 2.26:1 en tema oscuro.
   Con `--in-text` el par da 12.8:1 (claro) y 13.8:1 (oscuro), y el
   estado abierto se marca engordando el borde, no invirtiendo color. */
.in-chip.in-chip-attn {
  background: var(--in-orange-soft);
  border-color: var(--in-orange);
  color: var(--in-text);
}
.in-chip.in-chip-attn:hover:not(:disabled) { background: var(--in-orange-soft); }
.in-chip.in-chip-attn.active {
  background: var(--in-orange-soft);
  border-color: var(--in-orange);
  color: var(--in-text);
  box-shadow: inset 0 0 0 1px var(--in-orange);
}

/* ── Avatar circular sobre acento (v3.5) ──────────────────────────────
   Iniciales de una persona sobre el navy de marca. Blanco FIJO, como
   .in-btn-primary y .in-chip.active: componer `--in-text` sobre
   `--in-accent` da tinta sobre navy en tema claro (<2:1) — el mismo par
   que ya falló en el selector de la Biblioteca Mentor IN. */
.in-avatar-accent {
  background: var(--in-accent);
  color: var(--in-on-accent);
}

/* Fondo de momentum de un candidato del Máster (Mark, 17-oct): el grafismo de las cards de
   INcierto teñido por su momentum (verde alto · azul medio · cobre bajo) y la máscara RADAR.
   Lo usan la carta de la ficha y la tarjeta de los listados: una sola fuente para los dos.
   Uso:  <div class="in-fondo-momentum" data-nivel="alto|medio|bajo" aria-hidden /> como primer
   hijo de un contenedor con `position: relative; isolation: isolate; overflow: hidden`. */
.in-fondo-momentum { position: absolute; inset: 0; z-index: -1; }
.in-fondo-momentum, .in-fondo-momentum[data-nivel="medio"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(150, 200, 245, 0.5) 0%, rgba(150, 200, 245, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #3c6ea6 0%, #1d3a5c 55%, #0c1b30 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-momentum[data-nivel="alto"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(150, 235, 190, 0.45) 0%, rgba(150, 235, 190, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #2f8a5e 0%, #1b5a3d 55%, #0a2a1c 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-momentum[data-nivel="bajo"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(245, 200, 150, 0.45) 0%, rgba(245, 200, 150, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #a8673a 0%, #6b3c1f 55%, #2b170b 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-momentum::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(125% 105% at 0% 100%, rgba(4, 14, 26, 0.55) 0%, rgba(4, 14, 26, 0.2) 45%, rgba(4, 14, 26, 0) 75%); /* ds-hardcode-ok — máscara RADAR */
}

/* Fondo por FASE de un tema del tablero de Desarrollos (Mark, 19-oct: «un color de fondo que
   muestre en qué fase está, más frío o más caliente, con una opacidad en negro que deje leer»).
   Mismo grafismo que la carta de momentum. Escala con lógica (Mark, 19-oct: «que se distinga sin
   leer el nombre»): gris = nadie lo ha tocado · fríos = se está pensando (2 azul, 3 violeta,
   4 turquesa) · ámbar = en obra (5) · rojo = te toca a ti (6, como el 🔴 «Te toca») · verde =
   hecho (7). Tonos elegidos con el validador de paleta: todo par se distingue con visión normal
   (ΔE ≥ 15); azul↔violeta se confunden en protanopia y los separa el número + icono. La tinta encima es
   `--in-on-accent` y la máscara `::after` oscurece toda la tarjeta para garantizar la lectura.
   Uso: <div class="in-fondo-fase" data-fase="1..6" aria-hidden /> como primer hijo de un
   contenedor con `position: relative; isolation: isolate; overflow: hidden`. */
.in-fondo-fase { position: absolute; inset: 0; z-index: -1; }
.in-fondo-fase, .in-fondo-fase[data-fase="1"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(223, 229, 236, 0.35) 0%, rgba(223, 229, 236, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #7b8187 0%, #43474c 55%, #151618 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase[data-fase="2"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(203, 230, 255, 0.45) 0%, rgba(203, 230, 255, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #2c5dbd 0%, #0b2f76 55%, #07152f 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase[data-fase="3"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(249, 215, 255, 0.45) 0%, rgba(249, 215, 255, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #9d53b3 0%, #5c256c 55%, #200c26 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase[data-fase="4"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(174, 242, 255, 0.45) 0%, rgba(174, 242, 255, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #35cce6 0%, #007689 55%, #001b21 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase[data-fase="5"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(250, 226, 176, 0.45) 0%, rgba(250, 226, 176, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #eab532 0%, #8b6400 55%, #211300 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase[data-fase="6"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(255, 211, 205, 0.45) 0%, rgba(255, 211, 205, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #ba2b2e 0%, #71000a 55%, #2d0707 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase[data-fase="7"] {
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(200, 242, 200, 0.45) 0%, rgba(200, 242, 200, 0) 55%), /* ds-hardcode-ok — grafismo */
    linear-gradient(155deg, #399e43 0%, #015b14 55%, #031c05 100%); /* ds-hardcode-ok — grafismo */
}
.in-fondo-fase::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(rgba(4, 14, 26, 0.28), rgba(4, 14, 26, 0.28)), /* ds-hardcode-ok — velo para leer */
    radial-gradient(125% 105% at 0% 100%, rgba(4, 14, 26, 0.5) 0%, rgba(4, 14, 26, 0.15) 45%, rgba(4, 14, 26, 0) 75%); /* ds-hardcode-ok — máscara RADAR */
}

/* ── Distintivo / badge (v3.9) ────────────────────────────────────────
   Píldora corta que cuelga de un nombre y dice algo que cambia cómo tratas
   a esa persona: su rol en la comunidad, su estado de cobro, una sanción.

   Existía en el código como componente suelto (TarjetaBadge) con sus hex
   dentro, así que cada superficie que necesitaba una insignia se la volvía a
   inventar. Aquí hay TRES variantes y ninguna más (Mark 2026-08-20): gris si
   no hay nada que destacar, ámbar si pide atención, rojo si es grave. El
   color deja de ser decoración y vuelve a significar «mira esto».

   Nada de `color-mix()` para teñir el fondo: el minificador de producción lo
   parte en dos reglas y deja como respaldo el color de la tinta A PALO, o sea
   texto del mismo color que su fondo — invisible. Cada variante usa el par
   fondo/texto que el DS ya tiene medido para los dos temas.

   Uso:  <span class="in-badge in-badge-grave"> con un icono lucide de 11px. */
.in-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 100%;
  padding: 2px 8px 2px 6px;
  border-radius: var(--in-radius-pill);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--in-text-muted);
  background: var(--in-surface-deep);
  border: 1px solid var(--in-border);
}
.in-badge-atencion {
  /* `--in-warning-soft` es el ámbar de TEXTO, no el de estado: en claro es más
     oscuro (#8A6100 vs #9A6C00) y sobre el relleno ámbar sube de 4,2:1 a AA.
     A 10px eso no es un matiz — es legible o no lo es (medido en navegador). */
  color: var(--in-warning-soft);
  background: var(--in-warning-bg);
  border-color: var(--in-warning);
}
.in-badge-grave {
  color: var(--in-danger-text);
  background: var(--in-danger-bg);
  border-color: var(--in-danger);
}
/* Estado bueno (activo, incluido, al día). Texto en `--in-success-soft`, el
   verde de TEXTO: sobre su relleno da 5,4:1 en claro y 6,7:1 en oscuro
   (medido con scripts/audits/contrast.py, peor superficie de cada tema);
   `--in-success` en claro se queda en 4,4:1. Con icono, como las otras: el
   verde y el ámbar no se distinguen por color solo (deutan, §3.5). */
.in-badge-ok {
  color: var(--in-success-soft);
  background: var(--in-success-bg);
  border-color: var(--in-success);
}
/* «No renovación» (José, 2-nov-2026): ni sanción (rojo/ámbar) ni estado bueno; violeta propio.
   Tinta = `--in-role-mentor-ink`, ya medida como texto en los dos temas; relleno y borde derivados. */
.in-badge-norenov {
  color: var(--in-role-mentor-ink);
  background: color-mix(in srgb, var(--in-role-mentor-ink) 12%, transparent);
  border-color: color-mix(in srgb, var(--in-role-mentor-ink) 55%, transparent);
}
.in-badge > svg {
  width: 11px;
  height: 11px;
  flex: 0 0 auto;
}
/* Distintivo que además es enlace: mismo color y mismo relleno que su variante
   —un enlazado no es «otro tipo» de distintivo—, y la única señal de que se
   puede pulsar es el cursor y el subrayado al pasar por encima. */
a.in-badge {
  text-decoration: none;
  cursor: pointer;
}
a.in-badge:hover,
a.in-badge:focus-visible {
  text-decoration: underline;
}
.in-badge > span {
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Fila de distintivos bajo un nombre. */
.in-badges {
  display: contents;  /* la fila la pone el contenedor de la cabecera: los
                         distintivos fluyen junto al chip de producto en la
                         MISMA línea, no en un bloque aparte (Mark 2026-08-20) */
}

/* ── Link de texto (v3.1) ─────────────────────────────────────────── */
.in-link {
  color: var(--in-link);
  text-decoration: none;
  transition: color 0.12s;
}
.in-link:hover {
  color: var(--in-link-hover);
  text-decoration: underline;
}

/* ── Item de lista/nav/dropdown — estados canónicos (v3.1) ──────────────
   Para componer items con estado activo accesible (AA ≥3:1).
   Uso recomendado en React: aplicar inline o via className condicional. */
.in-item-active {
  background: var(--in-active-bg);
  color: var(--in-active-text);
  font-weight: 600;
}
.in-item-hover:hover:not(.in-item-active) {
  background: var(--in-hover-bg);
}

/* ── Focus visible accesible (WCAG SC 2.4.7) ─────────────────────────
   Aplicar a elementos interactivos custom (no nativos) cuando reciben
   foco por teclado. Los nativos (button, a, input) ya tienen sus propios
   anillos del browser; usar esta clase si se desea un look consistente. */
.in-focus-ring:focus-visible {
  outline: 2px solid var(--in-focus-ring);
  outline-offset: 2px;
}

/* ── Inputs sistema de diseño IN ──────────────────────────────────────── */
.in-input {
  width: 100%;
  background: var(--in-input-bg);
  color: var(--in-text);
  border: 1px solid var(--in-border-interactive);
  border-radius: var(--in-radius-md);
  padding: 10px 14px;
  font-size: 0.875rem;
  font-family: var(--in-font-body);
  transition: border-color 0.2s, box-shadow 0.2s;
  outline: none;
}
.in-input::placeholder {
  color: var(--in-text-subtle);
}
.in-input:focus {
  border-color: var(--in-accent);
  box-shadow: 0 0 0 3px var(--in-accent-glow);
}
.in-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* Estado inválido canónico (AUDIT-20260812): marcar con aria-invalid="true".
   El mensaje de error acompañante usa --in-danger-text (nunca --in-danger). */
.in-input[aria-invalid="true"] {
  border-color: var(--in-input-error-border);
  box-shadow: 0 0 0 3px var(--in-input-error-ring);
}

/* ── Contenedor con cabecera propia (v3.3, PLAN-20260707) ───────────────
   Patrón canónico del mockup v2: card con contorno definido cuya cabecera
   lleva franja propia + línea de cierre — se ve dónde empieza y dónde acaba.
   Adopción incremental: los Section locales migran aquí en la Fase 2. */
.in-section {
  background: var(--in-card);
  border: 1px solid var(--in-border-bright);
  border-radius: 14px;
  box-shadow: var(--in-shadow-card);
  overflow: hidden;
}
.in-section-title {
  font-family: var(--in-font-display);
  font-size: 11.5px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--in-text-subtle);
  background: var(--in-card-head-bg);
  border-bottom: 1px solid var(--in-card-head-border);
  padding: 10px 14px;
}
.in-section-body {
  padding: 14px;
}
/* Título de sección con un dato al lado («Usuarios con INcierto · 12»):
   el dato en minúscula normal para que no grite como el título. */
.in-section-title > .in-section-dato {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  color: var(--in-text-muted);
}

/* ── Cabecera de página (v3.9) ────────────────────────────────────────
   Un h1 y su explicación. Antes cada pantalla admin lo escribía a mano
   (5 variantes medidas: 20/22/28 px, 600/700/800, con y sin display). */
.in-page-title {
  font-family: var(--in-font-display);
  font-size: 22px;
  font-weight: 800;
  line-height: var(--in-leading-tight);
  letter-spacing: -0.01em;
  color: var(--in-text);
  margin: 0 0 4px;
}
.in-page-lede {
  font-size: 14px;
  line-height: var(--in-leading-normal);
  color: var(--in-text-muted);
  max-width: 72ch;
  margin: 0 0 20px;
}

/* ── Aviso (v3.9) ─────────────────────────────────────────────────────
   Resultado de una acción o aviso fijo: SIEMPRE icono lucide + texto
   (§3.5). El color de estado va en el borde izquierdo y en el icono; la
   tinta es `--in-text`, legible sobre los tres rellenos en los dos temas.
   Uso: <p class="in-aviso in-aviso--error" role="alert"><AlertCircle/>…</p> */
.in-aviso {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0;
  padding: 9px 12px;
  border-radius: var(--in-radius-sm);
  border-left: 3px solid var(--in-border-bright);
  background: var(--in-surface-deep);
  color: var(--in-text);
  font-size: 13.5px;
  line-height: var(--in-leading-normal);
}
.in-aviso > svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px; }
.in-aviso--ok { background: var(--in-success-bg); border-left-color: var(--in-success); }
.in-aviso--ok > svg { color: var(--in-success-soft); }
.in-aviso--atencion { background: var(--in-warning-bg); border-left-color: var(--in-warning); }
.in-aviso--atencion > svg { color: var(--in-warning-soft); }
.in-aviso--error { background: var(--in-danger-bg); border-left-color: var(--in-danger); }
.in-aviso--error > svg { color: var(--in-danger-text); }
.in-aviso--norenov { background: color-mix(in srgb, var(--in-role-mentor-ink) 10%, transparent); border-left-color: var(--in-role-mentor-ink); }
.in-aviso--norenov > svg { color: var(--in-role-mentor-ink); }

/* ── Tabla (v3.9) ─────────────────────────────────────────────────────
   Listado en columnas dentro de un `.in-section`. En móvil (<640) cada
   fila pasa a bloque y cada celda se rotula con su `data-label`: la tabla
   ya no se corta por la derecha (Mark, 2026-09-15, /admin/incierto).
   Uso: <table class="in-tabla"> … <td data-label="Estado">…</td>
   Una celda sin `data-label` (nombre, acciones) sale sin rótulo. */
.in-tabla {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  line-height: 1.45;
}
.in-tabla th {
  text-align: left;
  padding: 9px 12px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--in-text-subtle);
  background: var(--in-card-head-bg);
  border-bottom: 1px solid var(--in-card-head-border);
  white-space: nowrap;
}
.in-tabla td {
  padding: 11px 12px;
  vertical-align: top;
  border-top: 1px solid var(--in-border);
}
.in-tabla tbody tr:first-child td { border-top: none; }
.in-tabla tbody tr:hover { background: var(--in-hover-bg); }
.in-tabla .in-tabla-fin { text-align: right; }
.in-tabla .in-tabla-sec { color: var(--in-text-muted); }
@media (max-width: 639px) {
  .in-tabla thead { display: none; }
  .in-tabla, .in-tabla tbody, .in-tabla tr, .in-tabla td { display: block; width: 100%; }
  .in-tabla tr { padding: 10px 14px; border-top: 1px solid var(--in-border); }
  .in-tabla tbody tr:first-child { border-top: none; }
  .in-tabla td { padding: 5px 0; border-top: none; }
  .in-tabla td[data-label] {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr);  /* minmax: un nombre largo encoge, no empuja */
    gap: 10px;
    align-items: start;
  }
  .in-tabla td[data-label]::before {
    content: attr(data-label);
    font-size: 11.5px;
    color: var(--in-text-subtle);
    padding-top: 2px;
  }
  .in-tabla .in-tabla-fin { text-align: left; }
}

/* ── Campos etiqueta · valor (patrón B, elegido por Mark 2026-08-11) ───
   Pieza ÚNICA para mostrar datos en modo lectura (fichas, drawers, cards de
   detalle). Antes cada pantalla se lo inventaba con estilos en línea: la
   etiqueta salía en mayúsculas, semi-negrita y muy espaciada, compitiendo con
   un valor en negrita — dos cosas gritando y ninguna mandando.

   Reglas del patrón:
     · Manda el VALOR. La etiqueta es apoyo: minúsculas, gris, sin negrita.
     · Etiqueta a la izquierda (columna fija, alineada a la derecha) y valor
       a la derecha, como una ficha de toda la vida. Se recorre en vertical.
     · Línea fina entre filas: cada campo se lee como una unidad.
     · Cifras de ancho fijo (.in-num) para que las columnas de números cuadren.
     · Los huecos se escriben («Sin dirección»), no se dibujan con un guion.
   En pantallas estrechas la columna se apila sola (la etiqueta pasa arriba).

   Mockup validado: /mockups/ds-campos-etiqueta-valor/index.html
   Uso:
     <dl class="in-campos">
       <div class="in-campo">
         <dt class="in-campo-lbl">Móvil</dt>
         <dd class="in-campo-val in-num">+34 620 095 448</dd>
       </div>
     </dl>                                    (…-val.vacio para «Sin dato») */
.in-campos { display: block; }
.in-campo {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr);
  gap: 14px;
  align-items: baseline;
  padding: 10px 0;
  border-bottom: 1px solid var(--in-border);
}
.in-campo:last-child { border-bottom: none; }
.in-campo-lbl {
  font-size: 12px;
  font-weight: 500;
  line-height: 1.45;
  color: var(--in-text-muted);
  text-align: right;
}
.in-campo-val {
  min-width: 0;
  margin: 0;                       /* <dd> trae margen propio del navegador */
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.45;
  color: var(--in-text);
  overflow-wrap: anywhere;         /* emails largos no desbordan la card */
}
.in-campo-val.vacio {
  color: var(--in-text-muted);
  font-weight: 400;
}
/* Título de un grupo de campos DENTRO de una card (p. ej. «Sociedades
   conocidas»). Mismo criterio que las etiquetas: se lee, no grita. */
.in-campo-grupo {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--in-text-subtle);
  margin-bottom: 8px;
}
/* Cifras de ancho fijo: importes, teléfonos, DNI, códigos postales. El tamaño
   NO cambia (la tipografía dibuja las cifras a altura de mayúscula a propósito);
   lo que se corrige es el ancho variable, que descuadraba las columnas. */
.in-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
@media (max-width: 640px) {
  .in-campo { grid-template-columns: 1fr; gap: 1px; padding: 9px 0; }
  .in-campo-lbl { text-align: left; font-size: 11.5px; }
  /* Toques de 40 px en móvil (CHECKLIST-MAQUETA regla 4; lo midió el guardián de la publicación
     el 28-oct en Desarrollos: botones de icono de 34 px y segmentos de 36 px). `min-*` manda
     sobre el `width/height` inline de los botones de icono (tema, compartir). */
  button.in-focus-ring[aria-label] { min-width: 40px; min-height: 40px; }
  .in-segmented-btn { min-height: 40px; }
}

/* ── Separador con texto ─────────────────────────────────────────────── */
.in-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.75rem;
  color: var(--in-text-subtle);
}
.in-divider::before,
.in-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--in-border);
}

/* ── Nav responsive (bottom nav móvil / top nav desktop) ──────────────── */
.nav-bottom        { display: flex; }
.nav-desktop-links { display: none; }
.nav-bottom-spacer { height: calc(64px + env(safe-area-inset-bottom)); }

@media (min-width: 640px) {
  .nav-bottom        { display: none !important; }
  .nav-desktop-links { display: flex !important; }
  .nav-bottom-spacer { display: none !important; }
}

/* ── Checkboxes nativos sobre DS Opcion C (dark) ──────────────────────
   El styling nativo del browser + accent-color queda sin contraste sobre navy.
   Reemplazo con appearance:none + check SVG blanco. PRD-20260517-edicion-ficha-usuario. */
input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--in-border-bright);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.04);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.15s, border-color 0.15s;
  position: relative;
}

input[type="checkbox"]:hover:not(:disabled) {
  border-color: var(--in-accent);
}

input[type="checkbox"]:checked {
  background: var(--in-accent);
  border-color: var(--in-accent);
}

input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 1px;
  width: 5px;
  height: 10px;
  border: solid #FFFFFF;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

input[type="checkbox"]:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--in-accent-hover);
  outline-offset: 2px;
}

/* ── Interruptor (switch) del DS ──────────────────────────────────────
   Par encendido/apagado para estados binarios que hoy se resolvían con un
   <select> de dos opciones (p.ej. Activo/Descatalogado del catálogo de
   productos). Se monta sobre un <button role="switch"> para que sea accesible
   por teclado; el color viene de tokens, así que contrasta en ambos temas. */
.in-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  color: var(--in-text);
}
.in-switch:disabled { opacity: 0.5; cursor: not-allowed; }
.in-switch .in-switch-track {
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: var(--in-border-bright);
  position: relative;
  flex-shrink: 0;
  transition: background 0.15s;
}
.in-switch .in-switch-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #FFFFFF;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  transition: left 0.15s;
}
.in-switch[aria-checked="true"] .in-switch-track { background: var(--in-success); }
.in-switch[aria-checked="true"] .in-switch-knob { left: 21px; }
.in-switch .in-switch-label { font-size: 13px; font-weight: 700; }
.in-switch:focus-visible { outline: 2px solid var(--in-accent-hover); outline-offset: 3px; border-radius: 999px; }

/* ── CV: panel tab (debajo de la cabecera) responsive ─────────────────── */
@media (max-width: 639px) {
  .cv-panel-tab { padding: 10px 10px !important; margin-bottom: 12px !important; }
}

/* ── CV: sobre-mi mobile ─────────────────────────────────────────────── */
@media (max-width: 639px) {
  .cv-sobre-mi { margin-bottom: 12px !important; }
}

/* ── CV: nav bottom bar — ocultar label texto en mobile para más espacio ─ */
@media (max-width: 639px) {
  /* reducir padding del toolbar/breadcrumb */
  .curriculum-toolbar { padding: 8px 10px !important; min-height: unset !important; }
}

/* ── CV: tarjetas KPI stats ──────────────────────────────────────────── */
@media (max-width: 639px) {
  .cv-stat-card { padding: 8px 10px !important; }
  .cv-stat-card > div:first-child { font-size: 8px !important; margin-bottom: 2px !important; }
  .cv-stat-card > div:last-child, .cv-stat-card > div:nth-child(2) { font-size: 17px !important; }
}

/* ══════════════════════════════════════════════════════════════
   CV CABECERA — REDISEÑO MOBILE COMPLETO
   ≤600px: layout vertical (avatar centrado arriba + info abajo)
   >600px: layout horizontal original sin cambios
   ══════════════════════════════════════════════════════════════ */

/* — Padding lateral máximo aprovechado — */
@media (max-width: 639px) {
  .cv-content { padding: 0 !important; }
  .cv-header-card { padding: 12px 12px 0 !important; gap: 0 !important;
    flex-direction: column !important; align-items: stretch !important;
    border-radius: 0 !important; border-left: none !important; border-right: none !important; }

  /* Avatar: centrado + más pequeño */
  .cv-header-avatar {
    display: flex !important;
    justify-content: center !important;
    margin-bottom: 8px !important;
    flex-shrink: unset !important;
  }
  .cv-header-avatar img,
  .cv-header-avatar > div {
    width: 56px !important;
    height: 56px !important;
  }

  /* Info: ocupa todo el ancho */
  .cv-header-info { width: 100% !important; }

  /* h1 nombre: centrado en mobile */
  .cv-header-card h1 {
    font-size: 16px !important;
    text-align: center !important;
    word-break: break-word !important;
  }

  /* Fila nombre+botón: centrar en mobile */
  .cv-header-card h1 + div,
  .cv-header-info > div:first-child {
    justify-content: center !important;
    flex-wrap: wrap !important;
  }
}

/* — Tab bar: fade derecho indica scroll oculto — */
.cv-tab-bar-wrapper {
  position: relative;
  overflow: hidden;
}
.cv-tab-bar-wrapper::after {
  content: "";
  position: absolute;
  right: 0; top: 0; bottom: 1px; /* 1px para no tapar el border-bottom */
  width: 40px;
  background: linear-gradient(to right, transparent, var(--in-card));
  pointer-events: none;
  z-index: 1;
}

/* Tab bar sin scrollbar visible en todos los browsers */
.cv-tab-bar::-webkit-scrollbar { display: none; }
.cv-tab-bar { scrollbar-width: none; -ms-overflow-style: none; }

/* Panel tab más compacto en mobile */
@media (max-width: 639px) {
  .cv-panel-tab {
    border-radius: 0 !important;
    border-left: none !important;
    border-right: none !important;
    padding: 10px 12px !important;
    margin-bottom: 8px !important;
  }
  .cv-sobre-mi {
    border-radius: 0 !important;
    border-left: none !important;
    border-right: none !important;
    margin-bottom: 8px !important;
    padding: 12px !important;
  }
  /* KPI stats */
  .cv-stat-card { padding: 8px 10px !important; }
  .cv-stat-card > div:first-child { font-size: 8px !important; margin-bottom: 2px !important; }
}

/* ══════════════════════════════════════════════════════════════
   CV CABECERA v4 — Layout Mark (foto grande + info derecha)
   ══════════════════════════════════════════════════════════════ */

/* Avatar grande en mobile */
@media (max-width: 639px) {
  .cv-header-card {
    grid-template-columns: 88px 1fr !important;
    gap: 10px !important;
    padding: 10px 10px 0 !important;
  }
  .cv-header-avatar {
    align-items: flex-start !important;
  }
  .cv-avatar-img {
    width: 80px !important;
    height: 80px !important;
    border-radius: 10px !important; /* rectangular, más moderno que circular */
  }
  /* Nombre: grande */
  .cv-nombre { font-size: 18px !important; }

  /* Botón split restaurado en header — no ocultar */
  /* .cv-header-info > div:first-child > div:last-child — visible siempre */

  /* Fila de teléfonos con botón inline */
  .cv-contacto-bloque { gap: 3px !important; }
  .cv-tel-row, .cv-email-row { font-size: 11px !important; gap: 6px !important; }

  /* Botón refresh inline: solo visible en mobile */
  .cv-refresh-inline { display: inline-flex !important; }

  /* Tab bar: distribuido a todo el ancho, sin scroll */
  .cv-tab-bar { overflow-x: visible !important; }
  .cv-tab-bar-wrapper::after { display: none !important; } /* no fade si no hay scroll */
}

/* Desktop: ocultar el botón refresh inline (solo para mobile) */
@media (min-width: 640px) {
  .cv-refresh-inline { display: none !important; }
}

/* ── CV: tabs full-width (fuera de la columna info) ─────────────────── */
.cv-tab-bar-full {
  /* En la card con grid 2 cols, los tabs abarcan ambas columnas */
  grid-column: 1 / -1;
  margin-top: 8px;
}

/* En mobile: el card ya es grid, los tabs heredan el span */
@media (max-width: 639px) {
  .cv-tab-bar-full { margin-top: 6px; }
  /* nombre alineado izquierda (anular centrado anterior) */
  .cv-header-card h1 { text-align: left !important; }
}

/* ── Dashboard home: optimización mobile ───────────────────────────── */
.dash-bloque-header  { padding: 16px 22px; }
.dash-bloque-content { padding: 20px 22px; }
.fv-kpi-card { padding: 16px 18px; }
.fv-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
}

@media (max-width: 639px) {
  /* Bloques del dashboard: header y body con el mismo padding lateral.
     Subimos el lateral interno a 18px para que el texto respire dentro
     de la card (antes se pegaba a los bordes). */
  .dash-bloque-header  { padding: 14px 18px !important; }
  .dash-bloque-content { padding: 16px 18px !important; }
  /* KPI cards de Fuentes Vivas */
  .fv-kpi-card { padding: 14px 16px !important; }
  .fv-kpi-grid { gap: 10px !important; grid-template-columns: 1fr !important; }
}

/* ── PRD-20260604: Historial de pagos expandible — tamaños alineados a DS ──
   Mark detectó que en móvil los tamaños 10/11/12px del bloque legacy se leen
   demasiado pequeños. La regla sube un escalón en móvil sin romper el resto
   de la ficha (que sigue el patrón heredado). */
.in-historial-pagos {
  font-size: 14px;
}
.in-historial-pagos .in-hp-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--in-text-muted);
}
.in-historial-pagos .in-hp-label-sub {
  font-weight: 400;
  text-transform: none;
  font-size: 12px;
}
.in-historial-pagos .in-hp-resumen { font-size: 13px; line-height: 1.55; }
.in-historial-pagos .in-hp-resumen-meta { font-size: 12px; color: var(--in-text-muted); margin-top: 3px; }
.in-historial-pagos .in-hp-evento-titulo { font-size: 13px; font-weight: 600; color: var(--in-text); }
.in-historial-pagos .in-hp-evento-detalle { font-size: 12px; color: var(--in-text-muted); }
/* Trazabilidad de una devolución: de dónde sale + comprobación (Mark 2026-08-20).
   Bloque destacado dentro del evento, no una línea más de detalle. */
.in-historial-pagos .in-hp-traza {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 6px; padding: 8px 10px;
  border: 1px solid var(--in-border); border-radius: 8px;
  background: var(--in-surface); color: var(--in-text);
  font-size: 12px; line-height: 1.45;
}
.in-historial-pagos .in-hp-narrativa { font-size: 13px; color: var(--in-text); line-height: 1.55; }
.in-historial-pagos .in-hp-intento { font-size: 12px; color: var(--in-text-muted); }
.in-historial-pagos .in-hp-intento-ts { color: var(--in-text); font-weight: 500; }
.in-historial-pagos .in-hp-intento-nota {
  color: var(--in-text-subtle); font-style: italic; font-size: 12px;
  width: 100%; margin-top: 2px; line-height: 1.4;
}
.in-historial-pagos .in-hp-badge {
  font-size: 10px; font-weight: 700; padding: 3px 9px;
  border-radius: 12px; flex-shrink: 0; letter-spacing: 0.02em;
}

/* Móvil: subimos un escalón los tamaños (10→12, 12→13, 13→14, 14→15)
   y se sube el padding interior para que los chips no aprieten. */
@media (max-width: 639px) {
  .in-historial-pagos { font-size: 15px; }
  .in-historial-pagos .in-hp-label { font-size: 12px; }
  .in-historial-pagos .in-hp-label-sub { font-size: 13px; }
  .in-historial-pagos .in-hp-resumen { font-size: 14px; }
  .in-historial-pagos .in-hp-resumen-meta { font-size: 13px; }
  .in-historial-pagos .in-hp-evento-titulo { font-size: 14px; }
  .in-historial-pagos .in-hp-evento-detalle { font-size: 13px; }
  .in-historial-pagos .in-hp-narrativa { font-size: 14px; }
  .in-historial-pagos .in-hp-intento { font-size: 13px; }
  .in-historial-pagos .in-hp-intento-nota { font-size: 13px; }
  .in-historial-pagos .in-hp-badge { font-size: 11px; padding: 3px 10px; }
}

/* Portal del miembro — ancho responsive del shell (PLAN-20260706). Móvil: la
   misma columna estrecha de siempre. Laptop (≥760px, breakpoint ya usado por
   /portal/home): se ensancha en vez de quedarse como una tira móvil rodeada
   de vacío. */
@media (min-width: 760px) {
  :root { --portal-shell-w: 720px; }
}
/* Pantallas grandes: el shell se ensancha de verdad para que el portal se
   sienta pensado para desktop y no como una tira móvil centrada en el vacío. */
@media (min-width: 1200px) {
  :root { --portal-shell-w: 1040px; }
}
/* Pantalla muy ancha: un pelín más para aprovechar el ordenador (feedback Mark
   2026-07-17: "en el ordenador esta parte está sin aprovechar"). */
@media (min-width: 1600px) {
  :root { --portal-shell-w: 1160px; }
}
/* Oportunidades (Plataforma 2.0): UN ancho para todas sus pantallas y su cabecera
   (auditoría UI 2026-10-22: escaparate 1040, ficha 1240, Presentar 1120, Mi
   inversión 1180, y el logo no alineaba con el contenido). Lo lleva el envoltorio
   de cada pantalla; .ph-row hereda la variable. */
@media (min-width: 1000px) {
  /* El contenido lleva el mismo margen lateral que la cabecera (.ph-bar, 18 px) y
     --pw-caja = ancho + esos márgenes: su borde izquierdo cae bajo el logo. */
  .pw-ancho { --portal-shell-w: 1240px; --pw-caja: calc(1240px + 36px); }
}

/* ── Ventas del Programa IN (/admin/ventas) — responsive móvil ──────────
   La página monta el layout con estilos inline (spec del mockup v3, desktop);
   estas reglas los sobreescriben SOLO en móvil (mismo patrón que .cv-* y
   .dash-*: clase + !important para ganar al inline). */
@media (max-width: 639px) {
  /* KPIs: 2 columnas compactas */
  .ventas-kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 8px !important; }
  .ventas-kpi { padding: 10px 12px !important; }
  .ventas-kpi-val { font-size: 20px !important; }

  /* Cards: menos aire lateral, más ancho útil para gráficos y tablas */
  .ventas-card-head { padding: 10px 12px !important; }
  .ventas-card-body { padding: 12px !important; }

  /* Chips de vista/rango: un punto más pequeños para que quepan en 2 filas */
  .ventas-chips button { padding: 6px 11px !important; font-size: 12.5px !important; }

  /* Gráficos: algo menos altos en pantalla pequeña */
  .ventas-chart { height: 230px !important; }

  /* Filas de barra (embudo + canal): en desktop son grid de 3 columnas fijas
     que en móvil dejan la barra en nada; aquí se apilan — nombre y valor en
     la primera línea, barra a todo el ancho debajo. */
  .ventas-fila-barra {
    grid-template-columns: 1fr auto !important;
    grid-template-areas: "n v" "b b";
    row-gap: 4px !important;
  }
  .ventas-fila-nombre { grid-area: n; }
  .ventas-fila-bar { grid-area: b; }
  .ventas-fila-val { grid-area: v; }
  /* El "↓ pasa el X%" ya no tiene una columna de etiquetas a la que sangrarse */
  .ventas-embudo-pct { padding-left: 0 !important; }

  /* Zoom del mes: mini-KPIs siempre a 2 columnas */
  .ventas-zoom-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 8px !important; }

  /* Tablas (compras del mes · closers): celdas más compactas; el scroll
     horizontal del contenedor sigue siendo la vía para lo que no quepa */
  .ventas-table th { padding: 4px 6px 6px !important; }
  .ventas-table td { padding: 8px 6px !important; }
}

/* ── Campos de formulario en móvil: letra 16px SIEMPRE ──────────────────────
   iOS Safari hace zoom automático de página al enfocar cualquier campo con
   font-size < 16px. Ese zoom descoloca las barras fijas (bottom nav flotando
   en mitad de la pantalla) y desancla el menú de autorrelleno del teclado
   (llave/tarjeta/dirección "que no funciona") — reporte José 2026-07-27 en
   Respuestas a Discord, pero aplicaba a toda la webapp. El !important gana a
   los font-size inline (12-13px) de los componentes; solo actúa en móvil. */
@media (max-width: 639px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea {
    font-size: 16px !important;
  }
}

/* ── Catálogo "Contenido por producto": fila de módulo responsive ───────────
   En móvil el título del módulo ocupa todo el ancho y las acciones (Editar,
   eliminar) bajan a su propia línea. */
@media (max-width: 639px) {
  .pt-mod-row { flex-wrap: wrap !important; gap: 0 !important; }
  .pt-mod-toggle { flex: 1 1 100% !important; padding: 10px 12px 6px !important; }
}

/* ── Guardia anti-desborde horizontal (móvil) ───────────────────────────────
   Un solo texto sin espacios (URL larga, título tipo MTVV_1VIV_…) bastaba para
   ensanchar el documento: el móvil hace zoom-out y TODA la página queda
   "desmaquetada" a ~2/3 del ancho (reporte José 2026-07-27, pestaña Resueltos).
   `clip` no crea contenedor de scroll (no rompe position:sticky del header);
   fallback a hidden para navegadores sin soporte. */
html, body { overflow-x: clip; }
@supports not (overflow-x: clip) {
  body { overflow-x: hidden; }
}

/* ── DocuSeal embebido (firma del contrato y de las normas) ─────────────────
   El widget elige como contenedor de scroll el primer ancestro con overflow
   `scroll`/`auto`; si no encuentra ninguno cae a `document.scrollingElement`
   y, al enfocar el campo de firma (`scrollIntoField` → `scrollTo`, no lo tapa
   `autoscroll-fields=false`), scrollea LA PÁGINA ENTERA — al levantar el trazo
   la vista saltaba sola con la firma a medias (Didac 2026-08-05, verificado
   reproduciendo el stroke con Playwright: la página iba de 51.598 a 20.571).
   Haciendo scroller al propio elemento, ese movimiento se queda DENTRO del
   recuadro y el panel de firma no se mueve bajo el dedo. `min-height` gana a
   `max-height` en pantallas bajas, así que el recuadro nunca queda diminuto. */
docuseal-form {
  display: block;
  overflow-y: auto;
  overscroll-behavior: contain;
  min-height: 560px;
  max-height: 78vh;
}

/* ── Ventana modal abierta → fuera el botón flotante del Tutor IA ───────────
   El FAB del Tutor vive fijo en la esquina inferior derecha y queda por encima
   de las ventanas modales (su ancestro crea contexto de apilamiento, así que
   subir el z-index del overlay no basta). En una hoja inferior de móvil tapaba
   botones reales de la ventana. Quien abra un modal marca `<body>` con esta
   clase y el FAB se aparta mientras dure. */
body.in-modal-open .tf-fab { display: none; }

/* ── Selector desplegable con cards (v3.7) ─────────────────────────────
   Patrón «elegir personas/cosas de una rejilla» sin tener que pintar todo
   el catálogo siempre a la vista (el muro de chips de ponentes cargaba el
   formulario, feedback Mark 2026-08-18).

   · .in-pick-trigger — el control cerrado: se lee como un campo (mismo pozo
     y borde que .in-input) pero es un botón.
   · .in-pick-card    — cada card elegible. El estado elegido se marca con
     aria-pressed="true" y usa el par ya validado en ambos temas
     (--in-accent + blanco FIJO), el mismo de .in-btn-primary / .in-nav-card.
     NUNCA componer el activo con --in-text sobre --in-accent (tinta sobre
     navy en tema claro, <2:1). */
.in-pick-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 40px;
  text-align: left;
  padding: 7px 10px;
  border-radius: var(--in-radius-md);
  border: 1px solid var(--in-border-interactive);
  background: var(--in-input-bg);
  color: var(--in-text);
  cursor: pointer;
  box-sizing: border-box;
}
.in-pick-trigger:hover:not(:disabled) { border-color: var(--in-accent); }
.in-pick-trigger:focus-visible { outline: 2px solid var(--in-focus-ring); outline-offset: 2px; }

.in-pick-panel {
  border: 1px solid var(--in-border);
  border-radius: var(--in-radius-md);
  background: var(--in-surface-deep);
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.in-pick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
}

.in-pick-card {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 7px 9px;
  border-radius: var(--in-radius-md);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--in-border);
  background: var(--in-surface);
  color: var(--in-text-soft);
  transition: background .12s ease, border-color .12s ease;
}
.in-pick-card:hover:not([aria-pressed="true"]):not(:disabled) {
  background: var(--in-hover-bg);
  border-color: var(--in-accent);
}
.in-pick-card:focus-visible { outline: 2px solid var(--in-focus-ring); outline-offset: 2px; }
.in-pick-card[aria-pressed="true"] {
  background: var(--in-accent);
  border-color: var(--in-accent);
  color: var(--in-on-accent);          /* mismo par que .in-btn-primary */
}

/* ══════════════════════════════════════════════════════════════════════
   PRODUCTOS CANÓNICOS DEL MIEMBRO — configurador y resumen por familias
   Rediseño v0 «INfinito member dashboard» (Mark, 2026-08-18).
   Tres piezas:
     · .in-prod-cfg-*   configurador (modo edición de la ficha)
     · .in-prod-fam-*   resumen por familias (sección «Miembro»)
     · .in-prod-hero    chip destacado del producto principal (cabecera)
   Todo el color sale de tokens: contrasta en claro y en oscuro.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Configurador ──────────────────────────────────────────────────── */
.in-prod-cfg { display: flex; flex-direction: column; gap: 6px; }

.in-prod-row {
  border: 1px solid var(--in-border);
  border-radius: var(--in-radius-md);
  background: var(--in-surface-deep);
  transition: border-color .12s ease, background .12s ease;
}
.in-prod-row.is-on {
  border-color: var(--in-success);
  background: var(--in-success-bg);
}
.in-prod-row-main {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
}
/* Sangría + guía vertical: se ve de un vistazo que el producto DEPENDE del
   de arriba (feedback Mark: «mejora la percepción de dependencia»). */
.in-prod-row.is-child .in-prod-row-main { padding-left: 30px; }
.in-prod-row.is-child { margin-left: 18px; position: relative; }
.in-prod-row.is-child::before {
  content: "";
  position: absolute;
  left: -10px;
  top: -7px;
  bottom: 50%;
  width: 10px;
  border-left: 1px solid var(--in-border-bright);
  border-bottom: 1px solid var(--in-border-bright);
  border-bottom-left-radius: 6px;
}
.in-prod-arrow {
  flex-shrink: 0;
  color: var(--in-text-subtle);
  font-size: 13px;
  line-height: 1;
}
.in-prod-name {
  background: transparent;
  border: 0;
  padding: 0;
  text-align: left;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--in-text);
  cursor: pointer;
}
.in-prod-name:disabled { cursor: not-allowed; opacity: .6; }
.in-prod-meta { font-size: 11px; color: var(--in-text-subtle); margin-top: 2px; }

/* Etiqueta de tipo (Método · Especialización · Acompañamiento) */
.in-prod-kind {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: var(--in-radius-pill);
  border: 1px solid var(--in-border);
  background: var(--in-hover-bg);
  color: var(--in-text-muted);
  white-space: nowrap;
}
.in-prod-state {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 700;
  color: var(--in-text-subtle);
  white-space: nowrap;
}
.in-prod-row.is-on .in-prod-state { color: var(--in-positive); }

/* Ajustes del producto (solo cuando está activo) */
.in-prod-settings {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  padding: 0 12px 10px 52px;
}
.in-prod-row.is-child .in-prod-settings { padding-left: 70px; }
.in-prod-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.in-prod-field > span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--in-text-muted);
}
/* Controles compactos dentro del configurador: heredan .in-input del DS y
   solo ajustan la métrica (nunca el color). */
.in-prod-settings .in-input {
  width: auto;
  padding: 5px 9px;
  font-size: 12px;
  border-radius: var(--in-radius-sm);
  color-scheme: dark;
}
:root[data-theme="light"] .in-prod-settings .in-input { color-scheme: light; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .in-prod-settings .in-input { color-scheme: light; }
}

.in-prod-note {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: var(--in-radius-pill);
  background: var(--in-warning-bg);
  border: 1px solid var(--in-warning);
  color: var(--in-text);
  cursor: pointer;
}
.in-prod-note:disabled { cursor: default; }

/* Calculadora del precio de renovación (Mark 2026-09-04): ocupa toda la fila
   de ajustes porque enseña la tabla de tarifas por edición entera. */
.in-prod-calc {
  flex: 1 0 100%;
  margin-top: 2px;
  padding: 10px 12px;
  border: 1px solid var(--in-border);
  border-radius: var(--in-radius-md);
  background: var(--in-surface-deep);
  font-size: 12px;
  color: var(--in-text);
}
.in-prod-calc-cab { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.in-prod-calc-cab strong { font-size: 12.5px; }
.in-prod-calc-x {
  background: none; border: 0; padding: 2px; cursor: pointer; color: var(--in-text-subtle);
}
.in-prod-calc-sug { margin-top: 6px; line-height: 1.5; }
.in-prod-calc-nota { margin-top: 4px; font-size: 11.5px; color: var(--in-text-muted); }
.in-prod-calc-btn { margin-top: 8px; padding: 5px 12px; font-size: 12px; border-radius: var(--in-radius-sm); cursor: pointer; }
.in-prod-calc-vacio { margin-top: 6px; font-size: 12px; color: var(--in-text-muted); }
.in-prod-calc-tabla { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.in-prod-calc-tabla li {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 4px 8px; border-radius: var(--in-radius-sm);
}
.in-prod-calc-tabla li.es-suya { background: var(--in-surface); font-weight: 600; box-shadow: inset 2px 0 0 var(--in-positive); }
.in-prod-calc-ed { flex: 1 1 160px; min-width: 0; }
.in-prod-calc-eur { color: var(--in-text-muted); }
.in-prod-calc-eur em { font-style: normal; color: var(--in-text-subtle); }
.in-prod-calc-poner {
  padding: 3px 9px; font-size: 11px; font-weight: 600; cursor: pointer;
  border-radius: var(--in-radius-pill);
  border: 1px solid var(--in-border); background: transparent; color: var(--in-text);
}
.in-prod-calc-poner:disabled { cursor: default; opacity: .5; }
.in-prod-calc-pie { margin-top: 10px; font-size: 11.5px; color: var(--in-text-muted); }

.in-prod-empty {
  padding: 18px;
  text-align: center;
  font-size: 12px;
  color: var(--in-text-subtle);
}

/* ── Resumen por familias (sección «Miembro») ──────────────────────── */
.in-prod-fams {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.in-prod-fam {
  border: 1px solid var(--in-border);
  border-radius: var(--in-radius-md);
  background: var(--in-surface-deep);
  padding: 12px 14px;
}
.in-prod-fam.is-primary {
  border-color: var(--in-success);
  background: var(--in-success-bg);
}
.in-prod-fam h4 {
  margin: 0;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--in-text);
}
.in-prod-fam-sub { font-size: 11.5px; color: var(--in-text-muted); margin-top: 2px; }
/* Lista, no muro de pastillas: cada producto en su línea, con su matiz a la
   derecha (edición · de qué método cuelga · hasta cuándo). Se lee en vertical. */
.in-prod-fam-items {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.in-prod-fam-items > li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 5px 0;
  font-size: 12px;
  border-top: 1px solid var(--in-border);
}
.in-prod-fam-items > li:first-child { border-top: 0; }
.in-prod-fam-nom { font-weight: 600; color: var(--in-text); flex: 1; min-width: 0; }
/* Fecha de compra bajo el nombre (Mark 2026-09-22): «(estimada)» si se dedujo. */
.in-prod-fam-compra {
  display: block;
  margin-top: 1px;
  font-size: 11px;
  font-weight: 400;
  color: var(--in-text-muted);
}
.in-prod-fam-nota {
  flex-shrink: 0;
  font-size: 11px;
  color: var(--in-text-muted);
  white-space: nowrap;
}
/* Acompañamiento en vigor vs caducado/sin fecha: se ve sin leer la fecha. */
.in-prod-fam-items > li.es-ok .in-prod-fam-nota { color: var(--in-positive); font-weight: 600; }
.in-prod-fam-items > li.es-aviso .in-prod-fam-nota { color: var(--in-warning); font-weight: 600; }

/* ── Chip destacado de la cabecera ─────────────────────────────────── */
.in-prod-hero {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  /* A la talla de `.in-badge`: desde 2026-08-20 comparte fila con los
     distintivos del miembro y una sola escala hace que la fila se lea como
     una sola cosa. */
  font-size: 10px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--in-radius-pill);
  background: var(--in-active-bg);
  border: 1px solid var(--in-border-bright);
  color: var(--in-text);
  white-space: nowrap;
}
.in-prod-hero-rest { font-size: 10.5px; color: var(--in-text-muted); }

@media (max-width: 639px) {
  .in-prod-settings { padding-left: 12px; gap: 8px; }
  .in-prod-row.is-child .in-prod-settings { padding-left: 24px; }
  .in-prod-row.is-child { margin-left: 10px; }
  .in-prod-row.is-child .in-prod-row-main { padding-left: 20px; }
}

/* ── Menú «Opciones» de la ficha de miembro ────────────────────────────
   Se anclaba a la IZQUIERDA del botón (`left: 0`) con 256px fijos: en móvil
   el botón cae pegado al borde derecho y el menú se salía de la pantalla
   (Mark, 2026-08-18, captura en el móvil). Ahora se ancla a la derecha en
   pantallas estrechas y nunca supera el ancho del viewport. */
.cv-acciones-menu {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 4px;
  /* Por encima del botón flotante «FEED» (z-index 79), que si no tapa el
     último ítem del menú en móvil. */
  z-index: 82;
  min-width: min(256px, calc(100vw - 24px));
  max-width: min(320px, calc(100vw - 24px));
  border-radius: 8px;
  padding: 6px;
  background: var(--in-bg-mid);
  border: 1px solid var(--in-border);
  box-shadow: var(--in-menu-shadow);
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Un menú más alto que la pantalla tampoco se puede recorrer: que scrolle él. */
  max-height: calc(100vh - 140px);
  overflow-y: auto;
}
/* El velo. En escritorio solo captura el clic-fuera; en móvil, donde el menú
   es una hoja, se pinta para que la hoja se lea como una capa deliberada y no
   como una tarjeta suelta flotando encima del contenido. */
.cv-acciones-velo { position: fixed; inset: 0; z-index: 81; }

/* En móvil deja de colgar del botón: el botón puede caer en cualquier punto de
   la cabecera y anclarlo (a izquierda o a derecha) siempre lo sacaba por un
   lado. Pasa a hoja de acciones a ancho completo, pegada al borde inferior y
   por encima de la barra de navegación — el patrón que la gente ya conoce. */
@media (max-width: 900px) {
  .cv-acciones-velo { background: rgba(0, 0, 0, 0.5); }
  .cv-acciones-menu {
    position: fixed;
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    margin-top: 0;
    min-width: 0;
    max-width: none;
    max-height: min(78vh, calc(100vh - 96px));
    border-radius: 16px 16px 0 0;
    border-bottom: 0;
    padding: 8px 12px calc(14px + env(safe-area-inset-bottom));
    box-shadow: var(--in-sheet-shadow);
  }
  /* Asidero: marca que es una hoja y por dónde se agarra. */
  .cv-acciones-menu::before {
    content: "";
    display: block;
    width: 40px;
    height: 4px;
    margin: 2px auto 10px;
    border-radius: 999px;
    background: var(--in-border-bright);
    flex-shrink: 0;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   EDITAR FICHA — la edición como sección, no como modal
   Rediseño v0 «INfinito member dashboard» (Mark, 2026-08-19). Antes era un
   modal de 1100px con TODO el formulario apilado; ahora es una sección más
   del carril de la ficha, con sub-navegación propia y barra de guardado
   contextual.
   ══════════════════════════════════════════════════════════════════════ */
.cv-editor { padding-bottom: 96px; }

/* Sub-navegación: pastillas del DS. Pegajosa, para no perderse dentro de un
   formulario largo; con scroll horizontal cuando no caben. */
.cv-editor-nav {
  position: sticky;
  /* Misma referencia que el carril de secciones (top: 56) para que no se cuele
     bajo la barra superior en escritorio. */
  top: 56px;
  z-index: 5;
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 10px 0;
  margin-bottom: 4px;
  background: var(--in-bg);
}
.cv-editor-nav::-webkit-scrollbar { display: none; }
.cv-editor-nav .in-chip {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.cv-editor-badge {
  font-size: 10.5px;
  font-weight: 800;
  border-radius: var(--in-radius-pill);
  padding: 1px 7px;
  background: var(--in-warning-bg);
  color: var(--in-warning);
}
.in-chip.active .cv-editor-badge { background: var(--in-hover-bg); color: var(--in-on-solid); }

/* Aviso de comportamiento: se guarda solo vs necesita Guardar. */
.cv-editor-modo {
  margin: 0 0 14px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--in-text-muted);
  border-left: 3px solid var(--in-border-bright);
  padding-left: 10px;
}
.cv-editor-modo.es-auto {
  border-left-color: var(--in-success);
  color: var(--in-text-soft);
}

/* Barra de guardado: fija abajo, al alcance del pulgar, por encima de la barra
   de navegación del móvil y respetando el área segura. */
.cv-editor-barra {
  position: sticky;
  bottom: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: flex-end;
  padding: 12px 0 calc(12px + env(safe-area-inset-bottom));
  background: var(--in-bg);
  border-top: 1px solid var(--in-border);
}
.cv-editor-estado {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12px;
  color: var(--in-text-muted);
}

@media (max-width: 639px) {
  .cv-editor { padding-bottom: 20px; }
  .cv-editor-nav { top: 0; }
  .cv-editor-barra {
    bottom: calc(64px + env(safe-area-inset-bottom));
    padding-bottom: 12px;
  }
  .cv-editor-estado { flex-basis: 100%; margin-bottom: 2px; }
  .cv-editor-barra .in-btn-outline,
  .cv-editor-barra .in-btn-primary { flex: 1 1 0; justify-content: center; }
}

/* ══════════════════════════════════════════════════════════════════════
   VISTAS DE CONSUMO DE LA FICHA — lenguaje del diseño v0
   (Mark, 2026-08-19). Tres piezas: cabecera de sección con antetítulo,
   fila de KPIs y accesos a las otras secciones.
   ══════════════════════════════════════════════════════════════════════ */

/* Cabecera de sección: antetítulo · título · qué hay aquí. */
.cv-sec-head { margin-bottom: 16px; padding-bottom: 12px; border-bottom: 2px solid var(--in-accent); }
.cv-sec-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--in-text-muted);
}
.cv-sec-head h2 {
  margin: 4px 0 0;
  font-family: var(--in-font-display);
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--in-text);
}
.cv-sec-desc { margin: 3px 0 0; font-size: 12.5px; color: var(--in-text-muted); }

/* Fila de KPIs: lo que se necesita saber del miembro sin desplegar nada. */
.cv-kpis {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  margin-bottom: 16px;
}
.cv-kpi {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  border: 1px solid var(--in-border);
  border-radius: var(--in-radius-md);
  background: var(--in-card);
  padding: 12px 14px;
}
.cv-kpi-icon {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: var(--in-radius-sm);
  display: grid;
  place-items: center;
  font-size: 15px;
  background: var(--in-active-bg);
}
.cv-kpi-lbl {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--in-text-muted);
}
.cv-kpi-val {
  margin-top: 2px;
  font-family: var(--in-font-display);
  font-size: 18px;
  font-weight: 700;
  line-height: var(--in-leading-tight);
  color: var(--in-text);
}
.cv-kpi-nota { margin-top: 2px; font-size: 11px; color: var(--in-text-muted); }

@media (max-width: 639px) {
  .cv-sec-head { margin-bottom: 12px; }
  .cv-kpis { grid-template-columns: 1fr 1fr; gap: 8px; }
  .cv-kpi { padding: 10px; gap: 8px; }
  .cv-kpi-icon { width: 26px; height: 26px; font-size: 13px; }
  .cv-kpi-val { font-size: 15.5px; }
}

/* ─────────────────────────────────────────────────────────────────────────
   .in-theme-dark — superficie que SIEMPRE se ve en oscuro, esté el miembro en
   tema claro o no. El gemelo de `.in-theme-light`, que ya existía.

   Para qué: hay superficies que se comprometen deliberadamente con un único
   look porque su medio lo pide — una presentación a pantalla completa se
   proyecta y se exporta a PDF, y ahí el fondo es negro siempre. Sin esto
   heredaban los tokens del tema del navegador y salían rotas: el deck de
   `/presentacion/{id}` pinta su fondo oscuro a mano pero tomaba `--in-text`
   del tema, así que en modo claro escribía navy sobre casi negro (ilegible).
   La regla del DS sigue siendo la misma —nada de pares fondo/texto a mano—:
   lo que se fija aquí son los TOKENS, no los colores de cada control.

   Solo lleva los tokens que necesitan hoy esas superficies; si una necesita
   otro, se añade aquí (y no se escribe a mano en el componente).
   Los valores son EXACTAMENTE los del `:root` oscuro de arriba.
   Va al final del fichero y se dobla con el selector bajo `[data-theme=light]`
   para ganarle en especificidad pase lo que pase.
   ───────────────────────────────────────────────────────────────────────── */
.in-theme-dark,
html[data-theme="light"] .in-theme-dark {
  --in-bg:            #020610;
  --in-surface:       #0A1526;
  --in-surface-deep:  #060C16;
  --in-card:          #0F2039;
  --in-border:        rgba(255, 255, 255, 0.16);
  --in-border-bright: rgba(255, 255, 255, 0.30);
  --in-border-interactive: rgba(255, 255, 255, 0.65);
  --in-accent:        #003F72;
  --in-accent-glow:   rgba(0, 63, 114, 0.4);
  --in-danger:        #E65558;
  --in-danger-hover:  #c94448;
  --in-danger-text:   #ff8099;
  --in-positive:      #4ade80;
  --in-text:          #FFFFFF;
  --in-text-soft:     #E0EAF6;
  --in-text-muted:    #B0C6E0;
  --in-text-subtle:   #9BB6D4;
  --in-link:          #6FB3E8;
  --in-font-display:  'Montserrat', ui-sans-serif, sans-serif;
  --in-font-body:     'Inter', ui-sans-serif, sans-serif;
}

/* ═════════════════════════════════════════════════════════════════════════
   INcierto v4 — rediseño acotado a /incierto (2026-08-21, Mark)
   ─────────────────────────────────────────────────────────────────────────
   Diseño aprobado en Figma (docs/rediseno/20260821-incierto-v4/README.md).
   Lo que cambia, y por qué:
     · El navy de marca deja de ser el SUELO de la aplicación — sigue siendo el
       acento. En claro el trabajo pasa a papel frío; en oscuro, a grafito
       azulado (más neutro que el navy casi negro, para que el dato destaque).
     · Entra un acento COBRE propio de INcierto, reservado a lo que espera
       acción del gestor. Si todo es cobre, nada lo es.
     · El tramo alto del semáforo (`--in-ocean`) pasa de azul a TEAL: con el
       azul corporativo, «océano azul» se leía como «seleccionado».
     · Titulares en Sora (sustituto libre de Nohemi) y cifras en IBM Plex Mono.

   Por qué un ÁMBITO y no un cambio global: estos tokens los usa todo el
   portal. Redefinirlos en `:root` habría rediseñado de paso INfinito, el
   portal del alumno y el admin — que no es lo que se pidió. Aquí se redefinen
   solo dentro de `.inc-v4`, que el layout de /incierto pone en su raíz: todo
   lo que ya escribe `var(--in-*)` lo hereda sin tocar un solo componente, y
   revertirlo es quitar esa clase.

   Mismo patrón que `.in-theme-dark` de arriba: el bloque base cubre el tema
   oscuro (que es el `:root`) y el segundo, doblado bajo `[data-theme=light]`,
   gana en especificidad pase lo que pase.
   ═════════════════════════════════════════════════════════════════════════ */
.inc-v4 {
  /* superficies — grafito azulado en vez de navy casi negro */
  --in-bg:                  #05080D;
  --in-bg-mid:              #0B1119;
  --in-surface:             #111925;
  --in-surface-deep:        #0B1119;
  --in-card:                #18222F;
  --in-input-bg:            #080D14;
  --in-card-head-bg:        rgba(255, 255, 255, 0.05);
  --in-card-head-border:    rgba(255, 255, 255, 0.10);

  /* marca */
  --in-accent:              #0B4E7E;
  --in-accent-hover:        #0F6098;
  --in-accent-glow:         rgba(11, 78, 126, 0.45);
  /* cifra positiva (ingreso) ESCRITA SOBRE el acento — la tarjeta «Cuenta» de
     FINA. `--in-success` está medido sobre la tarjeta, no sobre el acento: en
     cada skin este token lleva el verde que sí se lee ahí (≥ 4.5:1). */
  --in-on-accent-positive:  #6EE7B7;

  /* texto */
  --in-text-soft:           #E2EAF4;
  --in-text-muted:          #B4C3D6;
  --in-text-subtle:         #8FA2B8;

  /* bordes — sólidos, no alfa: sobre grafito el alfa blanco lavaba la card */
  --in-border:              #22303F;
  --in-border-bright:       #33445A;
  --in-border-interactive:  #4A5D75;

  /* estados */
  --in-hover-bg:            #1B2532;
  --in-active-bg:           #123048;

  /* semáforo: el tramo alto deja de competir con el azul de marca */
  --in-ocean:               #2DD4BF;
  --in-ocean-bg:            rgba(45, 212, 191, 0.12);

  /* acento propio de INcierto: «esto espera algo de ti» */
  --in-copper:              #E08A4C;
  --in-copper-soft:         rgba(224, 138, 76, 0.14);
  --in-copper-solid:        #B0601F;   /* blanco encima: 5.0:1 ✓ */
  --in-copper-ink:          #FFFFFF;   /* texto sobre el cobre sólido */

  /* tipografía */
  --in-font-display:        'Sora', ui-sans-serif, sans-serif;
  --in-font-num:            'IBM Plex Mono', ui-monospace, monospace;
}

/* Tarjeta APAGADA (RADAR sin contenido, vía de ARCHI sin conectar): un estado,
   no una superficie — paleta clara FIJA, igual en claro y en oscuro (Mark
   2026-09-03), por eso no se dobla bajo [data-theme]. En `:root` y no en
   `.inc-v4`: las mismas tarjetas viven en la ficha de la Plataforma 2.0, fuera
   de ese ámbito, y allí se quedaban sin fondo ni borde (Mark, 2026-10-23). El
   skin de LoVivimos las sigue tiñendo en `.inc-v4` (PRD-20261012). Texto
   #0B2A45 sobre #E6EBF1 ≈ 12:1. */
:root {
  --in-apagada-bg:            linear-gradient(155deg, #F3F6FA 0%, #E6EBF1 100%);
  --in-apagada-border:        rgba(11, 42, 69, 0.30);
  --in-apagada-text:          #0B2A45;
  --in-apagada-text-soft:     #3F5971;
  --in-apagada-chip-text:     #2E4B66;
  --in-apagada-chip-bg:       rgba(11, 42, 69, 0.07);
  --in-apagada-chip-border:   rgba(11, 42, 69, 0.22);
  --in-apagada-btn-bg:        rgba(11, 42, 69, 0.06);
  --in-apagada-btn-border:    rgba(11, 42, 69, 0.45);
  --in-apagada-btn-hover-bg:  rgba(11, 42, 69, 0.14);
  --in-apagada-btn-hover-border: #0B2A45;
  --in-apagada-underline:     rgba(11, 42, 69, 0.35);
}

html[data-theme="light"] .inc-v4 {
  --in-bg:                  #F0F3F7;
  --in-bg-mid:              #F6F8FB;
  --in-surface:             #FFFFFF;
  --in-surface-deep:        #F4F7FB;
  --in-card:                #FFFFFF;
  --in-input-bg:            #FBFCFE;
  --in-card-head-bg:        #F4F7FB;
  --in-card-head-border:    #DCE4EE;

  --in-accent:              #06416A;   /* Pantone 7693C, sin tocar */
  --in-accent-hover:        #0A527F;
  --in-accent-glow:         rgba(6, 65, 106, 0.35);
  --in-on-accent-positive:  #6EE7B7;   /* menta sobre navy: 7.0 */

  --in-text-soft:           #2E4B66;
  --in-text-muted:          #4A6076;
  --in-text-subtle:         #5F7488;

  --in-border:              #DCE4EE;
  --in-border-bright:       #C3D0DF;
  --in-border-interactive:  #9FB1C4;

  --in-hover-bg:            #EDF1F6;
  --in-active-bg:           #E1EBF3;

  --in-ocean:               #0B7C8A;
  --in-ocean-bg:            rgba(11, 124, 138, 0.10);

  --in-copper:              #A85520;
  --in-copper-soft:         rgba(168, 85, 32, 0.10);
  --in-copper-solid:        #A85520;   /* blanco encima: 5.6:1 ✓ */
  --in-copper-ink:          #FFFFFF;

  --in-font-display:        'Sora', ui-sans-serif, sans-serif;
  --in-font-num:            'IBM Plex Mono', ui-monospace, monospace;
}

/* Titulares de INcierto en la display del ámbito. Los h1-h3 del producto ya
   la piden por token; esto cubre los que se pintan con clases propias. */
.inc-v4 h1,
.inc-v4 h2,
.inc-v4 h3 {
  font-family: var(--in-font-display);
  letter-spacing: -0.01em;
}

/* Cifras: mono con cifras tabulares, que es lo que hace que dos escenarios se
   puedan comparar columna con columna. `tnum` además fija el ancho del dígito
   para que un importe no baile al reescribirse. */
.inc-v4 .in-cifra {
  font-family: var(--in-font-num);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: -0.01em;
}

/* Lo que reclama acción del gestor. Relleno + borde en cobre y la etiqueta en
   tinta: el cobre como TEXTO sobre su propio relleno no llega a AA. */
.inc-v4 .in-atencion {
  background: var(--in-copper-soft);
  border: 1px solid var(--in-copper);
  color: var(--in-text);
}
.inc-v4 .in-btn-copper {
  background: var(--in-copper-solid);
  color: var(--in-copper-ink);
  border: none;
}
.inc-v4 .in-btn-copper:hover { filter: brightness(1.08); }

/* Cifras del producto en la mono del ámbito. Se listan aquí, y no clase a clase
   en cada pantalla, porque son los MISMOS cuatro sitios donde INcierto enseña
   dinero: los campos de escenario, el total, el margen y el mejor margen del
   listado. Solo se declara la familia y las cifras tabulares — el resto del
   estilo (tamaño, color, alineación) sigue viviendo donde vivía.
   `tabular-nums` es lo que hace que dos columnas de euros se puedan comparar
   dígito con dígito, y que un importe no baile al reescribirse. */
.inc-v4 .row input,
.inc-v4 .row .v,
.inc-v4 .margin-line .pct,
.inc-v4 .range-note b,
.inc-v4 .metric b,
.inc-v4 .in-cifra {
  font-family: var(--in-font-num);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: -0.01em;
}

/* ═════════════════════════════════════════════════════════════════════════
   SKIN LoVivimos — INcierto con la paleta y la tipografía de LoVivimos
   (PRD-20261012-incierto-skin-lovivimos, Mark 2026-10-12)
   ─────────────────────────────────────────────────────────────────────────
   Un skin es lo mismo que el ámbito `.inc-v4` de arriba: los tokens `--in-*`
   toman otros valores y todo lo que ya escribe `var(--in-*)` los hereda sin
   tocarse. Lo activa `html[data-skin="lovivimos"]`, que pone el layout de
   /incierto ANTES del primer paint leyendo `localStorage['in-skin']`
   (`web/lib/skin-incierto.ts`); la verdad vive en la preferencia `skin` del
   usuario (`incierto_preferencias`). Fuera de /incierto no hay `.inc-v4`,
   así que el resto del portal no cambia aunque el atributo esté puesto.

   Fuente de los valores: el sistema de diseño de LoVivimos
   (real-estate-app `frontend/app/globals.css` y `docs/features/design-system.md`):
   Poppins · marca amarillo #F9BE0D · tinta #27232D · papel #F4F4F4 · líneas
   #E7E7E9/#D5D6DA · ingreso #22C55E/#15803D · desviación #E5484D.
   LoVivimos tiene UNA sola versión (clara), así que este bloque gana a los
   dos temas: va después de `html[data-theme="light"] .inc-v4` con la misma
   especificidad y no se dobla bajo `[data-theme]`.

   `.in-skin-ficha` (Mark, 27-oct): la ficha de Oportunidades con la «Vista
   avanzada» encendida es INcierto dentro de otra pantalla, así que lleva el
   mismo skin; sin él, al fusionar las apps Mark perdió LoVivimos.

   Contraste medido (scripts/audits/contrast.py, 2026-10-12): tinta/blanco
   15.4 · muted #5B5F66 6.4 · subtle #6B7076 5.0 (4.5 sobre papel) · tinta
   sobre amarillo 9.1 (blanco sobre amarillo da 1.7: por eso existe
   --in-on-accent) · link #8A6100 5.5 · danger-text #C8302A 5.4 · success
   #15803D 5.0 · ocean #1D4ED8 6.7 · borde interactivo #8A9199 3.2.
   El gris de LoVivimos #98A0A8 (2.7) NO vale como texto: solo decorativo.
   ═════════════════════════════════════════════════════════════════════════ */
html[data-skin="lovivimos"] .inc-v4,
html[data-skin="lovivimos"] .in-skin-ficha {
  color-scheme: light;

  /* superficies — papel gris, tarjetas blancas */
  --in-bg:                  #F4F4F4;
  --in-bg-mid:              #FAFAFA;
  --in-surface:             #FFFFFF;
  --in-surface-deep:        #F4F4F4;
  --in-card:                #FFFFFF;
  --in-input-bg:            #FFFFFF;
  --in-overlay:             rgba(39, 35, 45, 0.55);
  --in-card-head-bg:        #F4F4F4;
  --in-card-head-border:    #E7E7E9;
  --in-map-filter:          none;

  /* líneas */
  --in-border:              #E7E7E9;
  --in-border-bright:       #D5D6DA;
  --in-border-interactive:  #8A9199;

  /* marca — amarillo con tinta oscura encima */
  --in-accent:              #F9BE0D;
  --in-accent-hover:        #E0AA00;
  --in-accent-glow:         rgba(249, 190, 13, 0.35);
  --in-on-accent:           #27232D;
  --in-on-accent-border:    rgba(39, 35, 45, 0.40);
  --in-on-accent-soft:      rgba(39, 35, 45, 0.12);
  --in-on-accent-positive:  #0A5527;   /* verde oscuro sobre amarillo: 5.3 (#15803D da 3.0) */
  --in-logo-ink:            #27232D;

  /* texto */
  --in-text:                #27232D;
  --in-text-soft:           #312D37;
  --in-text-muted:          #5B5F66;
  --in-text-subtle:         #6B7076;

  /* interacción */
  --in-link:                #8A6100;
  --in-link-hover:          #7A5600;
  --in-active-text:         #27232D;
  --in-active-bg:           rgba(249, 190, 13, 0.20);
  --in-hover-bg:            #F4F4F4;
  --in-focus-ring:          rgba(249, 190, 13, 0.70);
  --in-ghost-color:         rgba(39, 35, 45, 0.05);
  --in-ghost-hover:         rgba(249, 190, 13, 0.18);

  /* estados — los roles de dinero de LoVivimos (ingreso verde, desviación roja) */
  --in-danger:              #E5484D;
  --in-danger-hover:        #C8302A;
  --in-danger-glow:         rgba(229, 72, 77, 0.25);
  --in-danger-text:         #C8302A;
  --in-red-text:            #C8302A;
  --in-danger-bg:           #FED6D6;
  --in-success:             #15803D;
  --in-success-soft:        #15803D;
  --in-success-bg:          #DCFCE7;
  --in-positive:            #15803D;
  --in-positive-strong:     #15803D;
  --in-negative:            #C8302A;
  --in-warning:             #9A6C00;
  --in-warning-soft:        #8A6100;
  --in-warning-bg:          #FEF2CF;
  --in-ocean:               #1D4ED8;
  --in-ocean-bg:            rgba(59, 130, 246, 0.12);

  /* «esto espera algo de ti» = el amarillo de marca */
  --in-copper:              #F9BE0D;
  --in-copper-soft:         #FEF2CF;
  --in-copper-solid:        #F9BE0D;
  --in-copper-ink:          #27232D;

  /* tarjeta apagada: el azul grisáceo pasa a un amarillo muy claro con tinta
     (Mark 2026-10-12: «clarito, clarito»). #27232D sobre #FEF2CF ≈ 13:1;
     #5B5F66 sobre #FEF2CF ≈ 5.7:1. */
  --in-apagada-bg:            linear-gradient(155deg, #FFFCF0 0%, #FEF2CF 100%);
  --in-apagada-border:        rgba(249, 190, 13, 0.60);
  --in-apagada-text:          #27232D;
  --in-apagada-text-soft:     #5B5F66;
  --in-apagada-chip-text:     #4A4D52;
  --in-apagada-chip-bg:       rgba(249, 190, 13, 0.18);
  --in-apagada-chip-border:   rgba(249, 190, 13, 0.50);
  --in-apagada-btn-bg:        rgba(249, 190, 13, 0.22);
  --in-apagada-btn-border:    rgba(39, 35, 45, 0.35);
  --in-apagada-btn-hover-bg:  rgba(249, 190, 13, 0.50);
  --in-apagada-btn-hover-border: #27232D;
  --in-apagada-underline:     rgba(39, 35, 45, 0.35);

  /* el naranja de INcierto no existe en LoVivimos: tinta */
  --in-incierto:            #27232D;
  --in-incierto-text:       #27232D;
  --in-incierto-soft:       rgba(39, 35, 45, 0.06);
  --in-incierto-border:     rgba(39, 35, 45, 0.30);

  /* cabecera y sombras — planas, grises */
  --in-glass-bg:            rgba(255, 255, 255, 0.88);
  --in-glass-chip:          #FFFFFF;
  --in-glass-menu:          #FFFFFF;
  --in-topbar-shadow:       0 1px 0 #E7E7E9;
  --in-menu-shadow:         0 8px 28px rgba(39, 35, 45, 0.14);
  --in-sheet-shadow:        0 -8px 28px rgba(39, 35, 45, 0.14);
  --in-shadow-card:         0 1px 2px rgba(39, 35, 45, 0.04), 0 8px 24px -12px rgba(39, 35, 45, 0.12);
  --in-shadow-glow:         0 0 0 transparent;
  --in-shadow-2:            0 8px 24px rgba(39, 35, 45, 0.12);
  --in-shadow-3:            0 16px 40px rgba(39, 35, 45, 0.16);

  /* tipografía — una sola familia, como en LoVivimos; cifras tabulares */
  --in-font-display:        'Poppins', ui-sans-serif, sans-serif;
  --in-font-body:           'Poppins', ui-sans-serif, sans-serif;
  --in-font-num:            'Poppins', ui-sans-serif, sans-serif;
}

/* ── Pantalla de firma del Portal en móvil: el documento ES la pantalla ─────
   Con la regla de arriba el widget es su propio scroller (necesario: evita que
   la página salte al levantar el trazo), pero en móvil `min-height:560px` lo
   dejaba como una CAJITA con scroll propio dentro de una página que también
   scrolleaba: el documento se veía recortado y no se llegaba cómodamente a la
   zona de firma (Mark 2026-09-02).
   En móvil, mientras hay documento abierto, /portal/firma ocupa el viewport
   real (100dvh) y el documento se queda todo el hueco libre: un solo scroll,
   el del propio documento, y sin recorte. */
.portal-firma { min-height: 100vh; padding: 24px 14px 60px; }
.portal-firma__doc { min-height: 560px; }

/* Vale en TODOS los anchos, no solo en móvil: en una ventana de escritorio algo
   más ancha que 640px reaparecían los dos scrolls (Mark 2026-09-04). */
.portal-firma--doc {
  height: 100dvh;
  min-height: 0;
  padding: 12px 10px 10px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.portal-firma--doc .portal-firma__inner,
.portal-firma--doc .portal-firma__vista {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
/* El texto de apoyo sobra cuando el documento ya está delante: se cede su
   espacio al documento (el pie de «continuará sola» sí se mantiene). */
.portal-firma--doc .portal-firma__intro { display: none; }
.portal-firma--doc .portal-firma__doc { flex: 1; min-height: 0; }
.portal-firma--doc .portal-firma__doc docuseal-form {
  height: 100%;
  min-height: 0;
  max-height: none;
}

/* ── Firma a PANTALLA COMPLETA (components/firma/CapaFirmaDocuseal.tsx) ──
   Nació en el alta (Normas de la comunidad): dentro de la tarjeta del
   formulario convivían dos scrolls (página + widget) y firmar era incómodo en
   escritorio (Mark 2026-09-04). Como capa encima de todo queda un solo scroll:
   el del documento. Desde 2026-09-11 la comparten el alta y el contrato CCP
   del inversor; el componente bloquea la página de detrás. */
.firma-layer {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  flex-direction: column;
  background: var(--in-bg);
}
.firma-layer__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--in-border);
  background: var(--in-surface);
}
.firma-layer__cerrar {
  flex: 0 0 auto;
  padding: 8px 14px;
  font-size: 13.5px;
  border-radius: 10px;
}
.firma-layer__tit {
  font-family: var(--in-font-display, 'Montserrat'), sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--in-link);
}
.firma-layer__doc {
  flex: 1;
  min-height: 0;
  background: #fff;
  overflow: hidden;
}
.firma-layer__doc docuseal-form {
  height: 100%;
  min-height: 0;
  max-height: none;
}
.firma-layer__pie {
  margin: 0;
  padding: 9px 14px;
  border-top: 1px solid var(--in-border);
  background: var(--in-surface);
  color: var(--in-text-muted);
  font-size: 12px;
  line-height: 1.45;
}

/* ── Fila de lista con acciones (.in-fila) ───────────────────────────────
   Patrón «un elemento + sus acciones» dentro de una card de listado
   (personas autorizadas, contactos, invitaciones…).

   Por qué existe: el `display:flex; justify-content:space-between;
   flex-wrap:wrap` que se copiaba pantalla a pantalla se rompe en móvil —
   el nombre se parte en dos líneas y los botones caen debajo de forma
   distinta en cada fila (Mark, 2026-09-12, «Mis autorizados» en el móvil).
   Aquí la fila se APILA por defecto (nombre · detalle · acciones, cada
   cosa en su línea) y solo se pone en horizontal cuando hay sitio.

   Uso:
     <div class="in-fila">
       <div class="in-fila-quien">
         <span class="in-fila-nombre">Carol Moreno</span>
         <span class="in-fila-detalle">Oportunidad compartida</span>
       </div>
       <div class="in-fila-acciones">…botones o chips…</div>
     </div>
   El separador lo pone cada fila arriba; la primera de la card lo quita
   con `.in-fila:first-of-type` (por eso las filas han de ser hermanas). */
.in-fila {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 0;
  border-top: 1px solid var(--in-border);
  font-size: 13.5px;
  line-height: 1.45;
}
.in-fila:first-of-type { border-top: none; }
.in-fila-quien { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* `anywhere`: un nombre largo o un uuid no desbordan la card en 360 px. */
.in-fila-nombre { font-weight: 600; overflow-wrap: anywhere; }
.in-fila-detalle {
  color: var(--in-text-muted);
  font-size: 12.5px;
  overflow-wrap: anywhere;
}
.in-fila-acciones { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
@media (min-width: 620px) {
  .in-fila {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
  }
  .in-fila-acciones { flex-shrink: 0; }
}

/* Variante en TARJETA: para filas con más de un control (p. ej. ceder
   Fragua + Lystos), donde el separador fino no basta para ver qué
   pertenece a quién en una pantalla de móvil. */
.in-fila--card {
  border: 1px solid var(--in-border);
  border-radius: var(--in-radius-md);
  background: var(--in-surface-deep);
  padding: 12px 14px;
  margin-top: 8px;
}
 /* El `border-top:none` de `.in-fila:first-of-type` gana por especificidad:
    la tarjeta tiene que recuperar su borde superior aquí. */
.in-fila--card:first-of-type { margin-top: 0; border-top: 1px solid var(--in-border); }

/* ── Ayuda de un clic (v3.10, 2026-10-06 — rediseño ficha Plataforma 2.0) ──
   Botón (?) junto a la etiqueta de un campo; al pulsarlo despliega debajo,
   en el flujo, para qué sirve el dato. NO es un tooltip: funciona igual con
   el dedo que con el ratón (Didac: «ayuda de un clic, escritorio y móvil,
   no hover»). Componente: `web/components/ui/ayuda-campo.tsx`. */
.in-ayuda-btn {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: var(--in-radius-pill);
  background: transparent;
  color: var(--in-text-subtle);
  cursor: pointer;
  vertical-align: middle;
}
/* Zona táctil de 44 px sin mover el texto de alrededor. */
.in-ayuda-btn::before { content: ""; position: absolute; inset: -12px; }
.in-ayuda-btn:hover { color: var(--in-link); background: var(--in-hover-bg); }
.in-ayuda-btn:focus-visible { outline: 2px solid var(--in-focus-ring); outline-offset: 2px; }
.in-ayuda-btn[aria-expanded="true"] { color: var(--in-active-text); background: var(--in-active-bg); }
.in-ayuda-panel {
  margin: var(--in-space-2) 0 0;
  padding: var(--in-space-2) var(--in-space-3);
  border-radius: var(--in-radius-md);
  background: var(--in-surface-deep);
  border: 1px solid var(--in-border);
  font-size: 12px;
  font-weight: 400;
  line-height: var(--in-leading-normal);
  letter-spacing: normal;
  text-transform: none;
  color: var(--in-text-soft);
  white-space: normal;
}

/* ── Barra de progreso (v3.10) ─────────────────────────────────────────
   `<div class="in-progreso" role="progressbar" aria-valuenow…><i style="width:X%"></i></div>`.
   Una sola receta para completitud, captación e importación. */
.in-progreso {
  height: 8px;
  border-radius: var(--in-radius-pill);
  background: var(--in-surface-deep);
  border: 1px solid var(--in-border);
  overflow: hidden;
}
.in-progreso > i {
  display: block;
  height: 100%;
  background: var(--in-accent);
  transition: width var(--in-duration-slow) var(--in-ease-out);
}

/* Fila con scroll horizontal (pestañas): degradado en el borde por el que hay más.
   El lado lo calcula useDesbordeX (web/lib/use-desborde-x.ts) en data-mas. */
.in-desborde-x[data-mas~="der"] { -webkit-mask-image: linear-gradient(90deg, black calc(100% - 40px), transparent); mask-image: linear-gradient(90deg, black calc(100% - 40px), transparent); }
.in-desborde-x[data-mas~="izq"] { -webkit-mask-image: linear-gradient(90deg, transparent, black 40px); mask-image: linear-gradient(90deg, transparent, black 40px); }
.in-desborde-x[data-mas="izq der"] { -webkit-mask-image: linear-gradient(90deg, transparent, black 40px, black calc(100% - 40px), transparent); mask-image: linear-gradient(90deg, transparent, black 40px, black calc(100% - 40px), transparent); }

/* INfinito con menú lateral: la pantalla arranca pegada a la columna (menú → submenú →
   pantalla) aunque su contenedor venga centrado con `margin: 0 auto` (José, Looms 25-oct:
   «esta parte debería haberse ido a la izquierda… pegada»). Lo pone ShellLayout en escritorio. */
.in-main-izq > * { margin-left: 0 !important; }

/* «IN» de marca dentro de un nombre (Escaparate IN, Mis INversiones…): roja y en el peso más
   grueso de la display, como el logotipo (Mark, 4-nov). Componente: plataforma/TextoIN.tsx. */
.in-marca { color: var(--in-brand-red); font-family: var(--in-font-display); font-weight: 900; letter-spacing: -0.01em; }

/* Logotipo de la Plataforma IN: completo por defecto; en móvil, con miga de pan al lado, solo el
   bloque «IN» para que quepa «IN › Escaparate IN» en una fila (Mark, 4-nov). Con los interruptores de
   la ficha (.va-grupo) la miga baja a una segunda fila y el logo sigue completo. */
.pl-logo-icono { display: none; }
@media (max-width: 759px) {
  .ph-row:has(.pl-miga):not(:has(.va-grupo)) .pl-logo-completo { display: none; }
  .ph-row:has(.pl-miga):not(:has(.va-grupo)) .pl-logo-icono { display: inline-block; }
}
