/* ============================================================
   NEXOFEM — portal-v2.css · CAPA DE OVERRIDES (Josefa, 16-jul-2026)
   ETAPA 2 del rediseño de portales.
   ============================================================

   QUÉ ES ESTO
   -----------
   Capa ADITIVA de overrides. NO reemplaza a estilos.css: se carga
   DESPUÉS de él y solo escribe los DELTAS necesarios para llevar los
   portales vivos al look de los mockups aprobados (16-jul):
     · propuestas-portal/mock-medico-dashboard.html  (shell de referencia)
     · propuestas-portal/mock-paciente-cuenta.html
     · propuestas-portal/mock-admin-unificado.html

   CÓMO SE CARGA
   -------------
   En medico.html / super.html / admin.html / index.html, SIEMPRE después
   de estilos.css (y después de historia.css donde exista):
     <link rel="stylesheet" href="assets/css/estilos.css" />
     <link rel="stylesheet" href="assets/css/portal-v2.css" />

   ROLLBACK
   --------
   Quitar el <link>. estilos.css queda INTACTO -> el portal vuelve
   exactamente al estado Etapa 1. No hay nada más que revertir.

   REGLAS QUE ME AUTOIMPUSE AL ESCRIBIRLO
   --------------------------------------
   1. CONTRATO INTOCABLE: no se renombra ni se oculta nada que el JS
      use (.pantalla, #pantalla-*, .nav-item, .is-on, data-nav/-sup/-ad,
      IDs de inyección). Aquí solo hay pintura: color, espacio, radio,
      sombra, tipografía, borde.
   2. ACOTADO AL PORTAL: casi todo cuelga de .dash / .dash__side /
      .dash__main. Lo global se limita a refinamientos que no descuadran
      checkout.php, unirse.php, la sala ni el home del SPA.
   3. MEDIA QUERIES: como esta hoja carga ÚLTIMA, una regla mía sin
      media query le GANA a la misma regla dentro de un @media de
      estilos.css (el @media no suma especificidad). Por eso todo lo que
      colisiona con los breakpoints vivos (900 / 760 / 640 / 560) va
      envuelto en @media (min-width: …). Así el colapso responsive
      existente sigue mandando. Ver bloques marcados [GUARDA-MQ].
   4. Los sub-contenedores conservan su ancho: .pago-wrap 460,
      .sala 620, .login-wrap 410, .faq 760, .cont-doc 780. No se tocan.
   5. Estilos inline del JS (colores de .kpi__ic, .notif__ic, gradiente
      del hero de próxima consulta) GANAN siempre. No se pelean: ya
      calzan con la paleta del mockup.
   ============================================================ */

/* Tokens propios de esta capa. Nombres nuevos a propósito: no piso
   ningún token de estilos.css. */
:root {
  --v2-ease: cubic-bezier(.2, .7, .2, 1);
  --v2-spring: cubic-bezier(.16, 1, .3, 1);
}

/* ============================================================
   0) CONTRASTE DEL TEXTO TERCIARIO  (Josefa, 17-jul-2026)
   ============================================================
   ÚNICA excepción a la regla "no piso tokens de estilos.css", y va acá
   arriba a propósito: es una línea que corrige ~59 textos de una.

   EL PROBLEMA (medido en navegador, no estimado)
   ---------------------------------------------
   --tinta-3 = #8a86a8 REPRUEBA WCAG AA en TODOS sus fondos reales:
     · #ffffff (.panel)                 3.47:1   (AA exige 4.5)
     · #fdf9f6 (.dato-card)             3.31:1
     · #f7f4ff (.tabla thead th)        3.19:1
     · zebra tabla (aplanada #f8f7fd)   3.26:1
     · #f0eef6 (.slot.is-off)           3.02:1
     · #ede9ff (.cons-item__ic--off)    2.92:1   (UI exige 3.0 → tampoco)
   Lo usan 61 reglas. Es el gris de las fechas, folios, "hace 2 días",
   cabeceras de tabla y notas al pie: justo la letra chica que una
   paciente de 40+ NO alcanza a leer.

   POR QUÉ #656184 Y NO EL #44415c DEL MODO ALTO CONTRASTE
   ------------------------------------------------------
   El sistema YA tiene un gris correcto escondido en body.alto-contraste
   (#44415c, 9.74:1). Copiarlo acá sería el camino fácil y está MAL:
   medido en L* (claridad perceptual real, no el ratio WCAG que no es
   lineal), #44415c queda en L*=28.9 y --tinta-2 (#4a4573) en L*=31.7.
   O sea: el texto TERCIARIO quedaría MÁS OSCURO que el SECUNDARIO →
   la escalera se INVIERTE y el 3er nivel grita más que el 2º.
   En alto contraste eso no molesta porque ahí bajan los tres tokens
   juntos (--tinta y --tinta-2 se oscurecen también); suelto, rompe la
   jerarquía. Por eso NO se copia.

   #656184 es el punto medio elegido con dos reglas explícitas:
     (1) pasa 4.5:1 sobre el PEOR fondo de texto con ~20% de margen
         (5.38:1 sobre #f7f4ff) → no queda al filo de reprobar;
     (2) queda +11.0 L* MÁS CLARO que --tinta-2 → sigue leyéndose como
         3er nivel; la jerarquía se conserva.
   Y mantiene el TONO: HSL(247,15%) vs el HSL(247,16%) original. Es el
   mismo violeta-gris de siempre, solo más oscuro (L 59%→45%). No
   ensucia la paleta ni "cambia el diseño": cambia la legibilidad.

   ALCANCE — POR QUÉ ESTO NO SE ESCAPA A OTRAS PÁGINAS
   --------------------------------------------------
   Verificado archivo por archivo, no asumido:
     · portal-v2.css lo cargan SOLO index.html, medico.html y super.html.
     · checkout.php / unirse.php / subir-examenes.php / home.html tienen
       su propio <style> y NI SIQUIERA cargan estilos.css → inmunes.
     · consentimiento.html / recuperar.html / crear-clave.html cargan
       estilos.css pero NO esta hoja → siguen con #8a86a8, intactos.
     · Los correos y el PDF no pasan por acá.
   OJO (declarado, no accidental): index.html es la SPA completa, así que
   esto también aclara el flujo público de reserva (.med-card__uni,
   .slot.is-off, .candado, .step). Es DESEADO: hoy son igual de ilegibles
   y es donde la paciente decide.

   ALTO CONTRASTE: SIGUE FUNCIONANDO
   ---------------------------------
   body.alto-contraste (estilos.css:908) redefine --tinta-3 sobre <body>;
   esto lo hace sobre <html>. Como las custom properties heredan y <body>
   está más abajo, el modo alto contraste gana en sus descendientes y
   mantiene su #44415c. Verificado en navegador, no deducido.

   LOS 2 USOS DE --tinta-3 QUE SON FONDO Y NO TEXTO (auditados)
   -----------------------------------------------------------
     · estilos.css:830 .test-punto{background} → CSS MUERTO: ningún JS ni
       HTML lo pinta nunca (grep en todo el repo = 0). Impacto: cero.
     · historia.css:238 background: var(--ev-c, var(--tinta-3)) → es el
       FALLBACK de un punto de 14px; solo entra si un evento no trae clase
       de tipo, y todos la traen. Si entrara, el punto queda un poco más
       oscuro: inofensivo.
   ============================================================ */
:root {
  --tinta-3: #656184;
}

/* ============================================================
   1) TOPBAR — marca + acciones (mockup: blur con saturación,
      bajada de marca en violeta)
   ============================================================ */
.topbar {
  background: rgba(253, 249, 246, .82);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
}
/* "PORTAL MÉDICO" / bajada de la marca: del gris apagado al violeta de
   marca, con tracking. Global (la topbar es la misma en todo el sitio). */
.marca small {
  color: var(--violeta);
  font-weight: 600;
  letter-spacing: .12em;
}

/* ============================================================
   2) SHELL — .dash / .dash__side / .dash__main
   ============================================================ */

/* [GUARDA-MQ] Solo desde 901px. En <=900px manda el colapso a 1 columna
   de estilos.css:722. Si esto fuera sin @media, lo pisaría. */
@media (min-width: 901px) {
  .dash {
    grid-template-columns: 248px 1fr; /* mockup: sidebar 248 (vivo: 260) */
    gap: 26px;
  }
}

/* Tarjeta del sidebar. NO se toca `position`: el sticky top:92px vivo ya
   calza con la topbar real de 72px, y en <=900px estilos.css lo pasa a
   static (no lo piso).
   (17-jul: acá decía que el superadmin conservaba su barra horizontal vía
   `.dash--top .dash__side`. Quedó obsoleto: super.html:92 hoy es
   `class="dash dash--nav-groups"` y ya NO usa `dash--top` — se cambió al
   sidebar vertical agrupado en la Etapa 3. Ningún portal vivo trae
   `dash--top`, así que estas reglas aplican al superadmin sin competencia.) */
.dash__side {
  border: 1px solid var(--linea);
  padding: 16px;
}

/* Perfil del sidebar (acotado: .perfil__foto también vive en el perfil
   público del médico, que NO se toca). */
.dash__perfil {
  padding: 10px 0 14px;
}
.dash__perfil .perfil__foto {
  width: 66px;
  height: 66px;
  border-radius: 20px;
  margin: 0 auto 10px;
  box-shadow: var(--sombra-color);
}
/* Especialidad bajo el nombre: baja de jerarquía (mockup .perfil__r). */
.dash__perfil .med-card__esp {
  font-size: .82rem;
  color: var(--tinta-3);
  font-weight: 600;
}

/* ============================================================
   3) NAV-ITEM — menú lateral
   OJO: .is-on va con gradiente + texto blanco, como el MOCKUP APROBADO
   (el brief decía "violeta claro", pero eso es el HOVER del mockup; el
   activo es .grad-primario). Se sigue el mockup por ser la pieza
   aprobada por Mauricio. Contraste blanco/#5b4fcf ≈ 6.9:1 → AA ✓.
   ============================================================ */
.nav-item {
  gap: 11px;
  padding: 11px 13px;
  border-radius: 12px;
  font-size: .95rem;
  transition: background .2s var(--v2-ease), color .2s var(--v2-ease);
}
.nav-item svg {
  flex: none;
}
.nav-item:hover {
  background: var(--violeta-claro);
  color: var(--violeta);
}
.nav-item.is-on {
  background: var(--grad-primario);
  color: #fff;
  box-shadow: var(--sombra-sm);
}
/* "Cerrar sesión" en tono de salida. Se apunta por #nv-salir (el ID
   existe y el JS solo lo usa para innerHTML/listener: estilarlo no lo
   renombra ni lo toca). El vivo no tiene .is-danger. */
#nv-salir:hover {
  background: var(--rosa-claro);
  color: var(--rosa);
}

/* ============================================================
   4) PANEL / tarjetas — borde "glass" violeta + radio del mockup
   Global (el panel es el contenedor base del sistema), pero el delta
   es solo borde/padding: no mueve layout en checkout ni en la sala.
   ============================================================ */
.panel {
  border: 1px solid var(--linea);
  padding: 22px;
}

/* GUARDA: .liq-hero es `class="liq-hero panel"` (admin.js:170) y en
   estilos.css:656 declara border:none con la MISMA especificidad (0,1,0).
   Como esta hoja carga después, mi .panel le ganaría y le dibujaría un
   borde encima del gradiente. Se reafirma su intención original. */
.liq-hero {
  border: 0;
  box-shadow: var(--sombra-color);
}
/* GUARDA equivalente para las tarjetas de estado con barra lateral. */
.liq-estado-card--ok { border-left: 4px solid var(--ok); }
.liq-estado-card--pend { border-left: 4px solid var(--amarillo); }

/* Título de panel del portal (el HTML vivo usa <h3> con margen inline). */
.dash__main .panel > h3 {
  font-size: 1.15rem;
}

/* Anti-tell "card dentro de card": el hero de próxima consulta se inyecta
   como .panel DENTRO del .panel "Próximas consultas" (medico.js:158). Su
   fondo/borde vienen inline (ya son los del mockup); acá solo se le quita
   la sombra para que no se vea una tarjeta flotando sobre otra. */
#dash-citas > .panel {
  box-shadow: none;
}

/* Tarjetas de dinero del portal: mismo borde glass que el resto. */
.liq-card,
.cont-card {
  border-color: var(--linea);
}

/* ============================================================
   5) KPI — tarjeta de indicador
   El color de la pastilla .kpi__ic llega INLINE desde el JS
   (medico.js:132, admin.js:127, super.js:286) y ya usa la paleta del
   mockup. Acá solo tamaño, radio y tipografía.
   ============================================================ */
.kpi {
  border: 1px solid var(--linea);
  transition: transform .3s var(--v2-spring), box-shadow .3s var(--v2-ease);
}
.kpi:hover {
  transform: translateY(-4px);
  box-shadow: var(--sombra);
}
.kpi__ic {
  width: 44px;
  height: 44px;
  border-radius: 13px;
  margin-bottom: 12px;
}
.kpi b {
  font-family: var(--fuente-titulo);
  font-size: 1.9rem;
  line-height: 1;
  color: var(--tinta);
}
.kpi span {
  display: block;
  margin-top: 5px;
  font-size: .83rem;
}

/* ============================================================
   6) CITA-ROW — próximas consultas (mockup .cita)
   Acotado a .dash: .cita-row solo vive en medico/admin/super, todos
   dentro del shell. Pasa de "bloque con fondo gris" a "tarjeta con
   borde" y hover que la levanta hacia la derecha.
   ============================================================ */
.dash .cita-row {
  background: transparent;
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 13px 14px;
  transition: border-color .2s var(--v2-ease), transform .2s var(--v2-spring);
}
.dash .cita-row:hover {
  background: transparent;
  border-color: var(--lavanda);
  transform: translateX(3px);
}
/* La hora, en violeta y con la tipografía de titulares (mockup .cita__h). */
.dash .cita-row__hora b {
  font-family: var(--fuente-titulo);
  color: var(--violeta);
}
/* Cancelada: se conserva el atenuado vivo, sin que el hover la reviva. */
.dash .cita-row.is-cancelada:hover {
  transform: none;
  border-color: var(--linea);
}

/* ============================================================
   7) NOTIF — notificaciones (mockup: lista con separadores, sin fondo)
   El color de .notif__ic llega inline desde medico.js:359.
   ============================================================ */
.dash .notif {
  background: transparent;
  border-radius: 0;
  border-bottom: 1px solid var(--linea);
  padding: 12px 4px;
  margin-bottom: 0;
}
.dash .notif:last-child {
  border-bottom: 0;
}
.dash .notif__ic {
  width: 36px;
  height: 36px;
  border-radius: 11px;
}

/* ============================================================
   8) TABLAS densas — cabecera sobria + scroll DENTRO del contenedor
   El JS ya envuelve cada tabla en <div style="overflow:auto"> (super.js,
   admin.js, medico.js:1510). Ese wrapper se convierte en el .tbl-wrap del
   mockup vía :has(). Si un navegador no soporta :has(), simplemente no
   pinta el marco: la tabla sigue funcionando y scrolleando igual.
   ============================================================ */
div[style*="overflow"]:has(> table.tabla) {
  border: 1px solid var(--linea);
  border-radius: var(--r);
  background: var(--blanco);
  -webkit-overflow-scrolling: touch;
}

/* Cabecera: del bloque violeta a la cabecera sobria del mockup. */
.tabla thead th {
  background: var(--bg);
  color: var(--tinta-3);
  letter-spacing: .05em;
  border-bottom: 1.5px solid var(--linea);
}
.tabla tbody td {
  color: var(--tinta-2);
}
/* Zebra: se conserva (más tenue que el vivo) aunque el mockup no la trae.
   Motivo: las tablas del superadmin (auditoría, finanzas, citas) llegan a
   6-8 columnas y la banda ayuda a no perder la fila. El hover manda por
   encima. */
.tabla tbody tr:nth-child(even) td {
  background: rgba(91, 79, 207, .045);
}
.tabla tbody tr:hover td,
.tabla tbody tr:nth-child(even):hover td {
  background: var(--violeta-claro);
}

/* [GUARDA-MQ] El padding/tamaño de celda solo desde 641px: en <=640px
   manda la densidad compacta de estilos.css:430. */
@media (min-width: 641px) {
  .tabla thead th {
    padding: 13px 16px;
  }
  .tabla tbody td {
    padding: 13px 16px;
  }
}

/* ============================================================
   9) BOTONES — refinamiento GLOBAL conservador
   Solo peso, altura mínima (tap target ≥44px) y curva. NO se toca el
   padding global para no descuadrar checkout / sala / hero del home.
   ============================================================ */
.btn {
  font-weight: 600;
  min-height: 46px;
  transition: transform .25s var(--v2-spring), box-shadow .25s var(--v2-ease), background .25s var(--v2-ease);
}
/* 44px, no 40. El mínimo táctil (WCAG 2.2 "Target Size") es 44×44 y este
   piso decía 40: declaraba MENOS de lo exigido.
   Hoy NO hay bug visible — medido en navegador, el botón renderiza 44.3px
   reales en 1320/900/560/375, porque lo levanta el padding (10+10) más la
   línea de texto, no el min-height. Es decir: cumple por casualidad.
   El riesgo es silencioso: el día que alguien baje el padding o meta un
   btn--sm con texto más chico, el botón cae bajo 44 y NADIE se entera
   (no rompe nada, solo se vuelve difícil de apretar en un teléfono).
   Subirlo a 44 es no-op HOY (44 < 44.3, no ata) y red de seguridad mañana.
   Se usa en 109 lugares de los 3 portales; verificado que ninguno cambia. */
.btn--sm {
  min-height: 44px;
}
/* Ghost: gana el borde y el texto violeta del mockup (antes: texto tinta
   sin borde). Contraste #5b4fcf sobre blanco = 9.8:1 → AA ✓. */
.btn--ghost {
  color: var(--violeta);
  border: 1.5px solid var(--linea);
}
.btn--ghost:hover {
  border-color: var(--lavanda);
}

/* DESVIACIÓN DELIBERADA DEL MOCKUP (accesibilidad):
   el mockup pinta .btn--menta con texto BLANCO sobre el gradiente menta
   (#0fa896) = ~2.9:1 → REPRUEBA WCAG AA. El vivo usa #073b32 y pasa.
   Se mantiene el vivo: no se copia ese detalle del mockup. */

/* ============================================================
   ============================================================
   ETAPA 3 — reglas para la ESTRUCTURA nueva de los previews
   ============================================================
   Todo lo que sigue solo entra en juego si el HTML trae el marcado
   nuevo (.main-grid, .login-v2, .nav-group, .topbar__av). En los
   portales vivos (sin ese marcado) estas reglas no matchean nada:
   por eso portal-v2.css se puede seguir cargando en cualquiera de los
   dos sin efectos colaterales.
   ============================================================ */

/* ------------------------------------------------------------
   E3.1) DASHBOARD 2 COLUMNAS — el delta que faltaba
   Consultas (dominante) + notificaciones (lateral), como el mockup.
   ------------------------------------------------------------ */
.main-grid {
  display: grid;
  grid-template-columns: 1.55fr .9fr;
  gap: 22px;
  align-items: start;
}
/* Colapso propio a 1 columna. 980px es el breakpoint del mockup; queda por
   encima del colapso del .dash (900) para que el main nunca quede con dos
   columnas apretadas mientras el sidebar todavía es lateral. */
@media (max-width: 980px) {
  .main-grid {
    grid-template-columns: 1fr;
  }
}
/* Los .panel del grid ya no necesitan el margen inferior de la pila. */
.main-grid > .panel {
  margin-bottom: 0;
}

/* ------------------------------------------------------------
   E3.2) TOPBAR — rol + avatar
   ------------------------------------------------------------ */
.topbar__rol {
  /* inline-block, NO inline-flex: text-overflow solo aplica a un contenedor de
     bloque. Con inline-flex el texto queda en una caja anónima y el "…" nunca se
     pinta. Como .topbar__rol es hijo flex de .topbar__acc (align-items:center),
     el display se blockifica igual y el centrado vertical no cambia. */
  display: inline-block;
  font-family: var(--fuente-titulo);
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--violeta);
  background: var(--violeta-claro);
  padding: 6px 12px;
  border-radius: 999px;
  /* Tope de seguridad: el contenido lo pone la BD, no nosotros. "Dra. María
     Fernanda · Ginecología y Obstetricia Materno-Fetal" es un valor perfectamente
     legal y sin tope empujaría la marca fuera de la topbar. El texto completo
     queda en el title (lo pone medico.js).

     40vw y no 30vw: Renata midió en navegador real que con 30vw la pill truncaba
     entre 561px y 736px de viewport AUNQUE sobrara espacio en la topbar — y ahí el
     title no rescata nada, porque en pantalla táctil no hay hover. Con 34ch=247px
     medidos (ojo: uppercase + letter-spacing), el caso real más largo de la BD
     ("Dr. Ignacio · Endocrinología" = 221px) entra sin truncarse en todo el rango
     en que la pill es visible (>543px; bajo eso es display:none). */
  max-width: min(34ch, 40vw);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topbar__av {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--grad-primario);
  color: #fff;
  font-family: var(--fuente-titulo);
  font-weight: 700;
  font-size: .9rem;
  flex: 0 0 auto;
}
.topbar__av svg {
  width: 19px;
  height: 19px;
}
/* En móvil la marca ya suelta su bajada (estilos.css:736); el pill de rol
   sobra y se va, el avatar queda. */
@media (max-width: 560px) {
  .topbar__rol {
    display: none;
  }
}

/* ------------------------------------------------------------
   E3.3) NAV-GROUP — menú agrupado del superadmin
   ------------------------------------------------------------ */
.nav-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 14px;
}
.nav-group__lbl {
  font-family: var(--fuente-titulo);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--tinta-3);
  padding: 0 13px;
  margin-bottom: 6px;
}
/* "Cerrar sesión": separado del resto por una línea, no por un título. */
.nav-group--fin {
  margin-bottom: 0;
  padding-top: 10px;
  border-top: 1px solid var(--linea);
}
.nav-group--fin .nav-item:hover {
  background: var(--rosa-claro);
  color: var(--rosa);
}
/* El sidebar del superadmin lleva 13 items + 4 títulos: se le permite scroll
   propio para que nunca empuje el layout ni tape el contenido. */
@media (min-width: 901px) {
  .dash--nav-groups .dash__side {
    max-height: calc(100vh - 110px);
    overflow-y: auto;
  }
}

/* ------------------------------------------------------------
   E3.4) LOGIN "HERO PARTIDO"
   OJO: no se usa el patrón .paso{display:none}/.is-on del mockup. El JS
   vivo manda con [hidden] sobre #form-login / #form-login-2fa y esa sigue
   siendo la única fuente de verdad. Aquí solo se acompaña.
   ------------------------------------------------------------ */
.login-v2 {
  width: 100%;
  max-width: 1080px;
  margin-inline: auto;
  background: var(--blanco);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra);
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

/* --- Panel de marca --- */
.login-v2__brand {
  position: relative;
  background: var(--grad-primario);
  color: #fff;
  padding: clamp(28px, 4vw, 48px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.login-v2__brand::before,
.login-v2__brand::after {
  content: "";
  position: absolute;
  border-radius: 50%;
}
.login-v2__brand::before {
  left: -50px;
  top: -50px;
  width: 200px;
  height: 200px;
  background: radial-gradient(circle, rgba(255, 255, 255, .10), transparent 70%);
}
.login-v2__brand::after {
  right: -70px;
  bottom: -70px;
  width: 280px;
  height: 280px;
  background: radial-gradient(circle, rgba(255, 255, 255, .14), transparent 70%);
}
/* Logo a 20px: el −40% que pidió Mauricio sobre los 34px del mockup original.
   OJO: .login-v2__brand es flex-column → `align-items:stretch` (default) estiraba
   la <img> a TODO el ancho del panel y la dejaba como banner desproporcionado.
   `align-self:flex-start` la saca del stretch; sin esto, el height no basta. */
.login-v2__logo {
  height: 20px;
  width: auto;
  align-self: flex-start;
  max-width: 160px;
  object-fit: contain;
  position: relative;
  z-index: 2;
}
.login-v2__mid {
  margin-top: auto;
  position: relative;
  z-index: 2;
}
.login-v2__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--fuente-titulo);
  font-weight: 600;
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: .9;
}
.login-v2__eyebrow .dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #fff;
  opacity: .85;
}
.login-v2__brand h2 {
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2rem);
  margin: 14px 0 10px;
  line-height: 1.12;
  color: #fff;
}
.login-v2__brand p {
  opacity: .9;
  font-size: 1rem;
  max-width: 34ch;
}
.login-v2__feats {
  margin-top: 26px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.login-v2__feat {
  display: flex;
  align-items: center;
  gap: 11px;
  font-size: .92rem;
}
.login-v2__feat .ic {
  width: 36px;
  height: 36px;
  border-radius: 11px;
  background: rgba(255, 255, 255, .16);
  display: grid;
  place-items: center;
  flex: none;
}
.login-v2__feat .ic svg {
  width: 19px;
  height: 19px;
}

/* --- Panel de formulario --- */
.login-v2__form {
  padding: clamp(28px, 4vw, 52px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.login-v2__h {
  margin-bottom: 22px;
}
.login-v2__h h1 {
  font-size: clamp(1.4rem, 1.1rem + 1.1vw, 1.8rem);
  color: var(--tinta);
}
.login-v2__h p {
  color: var(--tinta-2);
  font-size: .94rem;
  margin-top: 6px;
}
/* Cuando el JS oculta el paso 1, su cabecera se va sola: no hay "Ingresa a tu
   portal" encima de "Verificación en dos pasos". Reacciona al [hidden] real,
   sin JS nuevo. Si el navegador no soporta :has(), la cabecera simplemente se
   queda (degradación fea pero inofensiva). */
.login-v2__form:has(#form-login[hidden]) .login-v2__h {
  display: none;
}

/* Inputs con ícono */
.login-v2 .campo {
  margin-bottom: 16px;
}
.login-v2 .campo label {
  font-size: .85rem;
  font-weight: 600;
  color: var(--tinta-2);
  margin-bottom: 6px;
}
.login-v2 .inp {
  position: relative;
}
.login-v2 .inp > svg {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  color: var(--tinta-3);
  pointer-events: none;
}
.login-v2 .inp input {
  width: 100%;
  border: 1.5px solid var(--linea);
  border-radius: 12px;
  padding: 13px 14px 13px 42px;
  font-size: .98rem;
  min-height: 50px;
  background: var(--bg-2);
}
.login-v2 .inp input:focus {
  outline: none;
  border-color: var(--lavanda);
  background: #fff;
  box-shadow: 0 0 0 4px var(--violeta-claro);
}
/* Código 2FA: sin ícono, centrado y espaciado (antes venía por estilo inline). */
.login-v2 .cod .inp input {
  padding-left: 14px;
  text-align: center;
  letter-spacing: .35em;
  font-size: 1.4rem;
  font-family: var(--fuente-titulo);
  font-weight: 700;
}

/* Cabecera del paso 2FA */
.login-v2__2fa-head {
  text-align: center;
  margin-bottom: 20px;
}
.login-v2__2fa-ic {
  width: 60px;
  height: 60px;
  border-radius: 18px;
  margin: 0 auto 12px;
  background: var(--violeta-claro);
  color: var(--violeta);
  display: grid;
  place-items: center;
}
.login-v2__2fa-ic svg {
  width: 30px;
  height: 30px;
}
.login-v2__2fa-head h1 {
  font-size: 1.5rem;
}
.login-v2__2fa-head p {
  color: var(--tinta-2);
  font-size: .92rem;
  margin-top: 6px;
}
.login-v2__altrow {
  text-align: center;
  margin-top: 14px;
}
.login-v2__altrow a {
  font-size: .88rem;
  color: var(--violeta);
  font-weight: 600;
  font-family: var(--fuente-titulo);
}
.login-v2__backrow {
  text-align: center;
  margin-top: 6px;
}
.login-v2__backrow a {
  font-size: .85rem;
  color: var(--tinta-2);
}
.login-v2 #login-nota {
  margin-top: 18px;
}

/* Colapso: el panel de marca se achica y suelta las features (mockup 820px). */
@media (max-width: 820px) {
  .login-v2 {
    grid-template-columns: 1fr;
    max-width: 460px;
  }
  .login-v2__brand {
    padding: 26px 26px 22px;
  }
  .login-v2__mid {
    margin-top: 20px;
  }
  .login-v2__feats {
    display: none;
  }
}

/* ============================================================
   10) MOVIMIENTO REDUCIDO
   estilos.css:754 ya mata animaciones y transiciones con !important.
   Acá se neutralizan además los desplazamientos de hover que introduce
   esta capa (sin transición, saltarían de golpe).
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .kpi:hover,
  .dash .cita-row:hover {
    transform: none;
  }
}

/* ============================================================
   11) MI CUENTA (PACIENTE) — vistas de SOLO LECTURA
       (Mateo, 16-jul-2026 · Tanda 1 de 2)
       Referencia: propuestas-portal/mock-paciente-cuenta.html (aprobado).
       Cubre: historial · mi ficha · mis documentos · mis consentimientos.
       NO cubre: "próximas consultas" / .hero-cita (va en la Tanda 2, que
       toca el camino crítico "unirse"/"reprogramar" y lleva QA propio).

   POR QUÉ ESTAS CLASES Y NO LAS DEL MOCKUP, TAL CUAL
   --------------------------------------------------
   El mockup es autocontenido y se permite redefinir nombres genéricos.
   En el portal vivo esos nombres YA EXISTEN y son COMPARTIDOS. Verificado
   uno por uno antes de escribir:
     · .tag      -> estilos.css:520, la usan paciente y super. El mockup la
                    repinta de celeste. NO SE TOCA: repintarla cambiaría
                    etiquetas en todo el portal.
     · .doc-item -> NO tiene CSS propio en el portal (el bloque de comun.js:237
                    vive dentro del window.open de UI.documento, otro documento).
                    En cambio super.js SÍ la usa en 4 lugares de su portal
                    (auditoría, adjuntos, citas). Estilarla como el mockup
                    habría pisado el superadmin -> se deja intacta y el
                    paciente pasa a .doc-card, que es suya.
     · .chip     -> estilos.css:623 es el filtro pill, y su .chip:hover (0,2,0)
                    le ganaría al color de un modificador (0,1,0). Por eso
                    .chip--conf / .chip--hecha son AUTÓNOMOS: se usan SIN la
                    clase .chip base, así ni :hover ni .is-on los alcanzan.
     · --ambar / --ambar-claro / --coral-claro del mockup NO EXISTEN acá.
                    El equivalente vivo es --durazno / --durazno-claro
                    (mismo #d4870a / #fbf0da). Cada var() de este bloque está
                    verificada contra el :root de estilos.css.
   MEDIA QUERIES: salvo .docs-grid, todas las clases de abajo son NUEVAS, así
   que no hay ninguna regla de estilos.css a la que puedan ganarle desde fuera
   de un @media. Sus breakpoints se declaran acá mismo y mandan por orden.
   ============================================================ */

/* --- Encabezado de panel del mockup (ícono + título). Clase nueva: no
       existía en el portal, donde los paneles abrían con un <h3> suelto. --- */
.panel__h {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 16px;
}
.panel__h svg {
  width: 20px;
  height: 20px;
  color: var(--violeta);
  flex: none;
}
.panel__h h2 {
  font-size: 1.15rem;
  margin: 0;
}

/* Apilado vertical de paneles (el mockup usa una sola columna ancha en estas
   vistas, en vez del .split 0.9/1.1 que traía "Mi ficha"). */
.cuenta-stack {
  display: grid;
  gap: 18px;
}

/* --- Fila de cita / atención (historial). La estrena el historial; la
       Tanda 2 la reusa para "próximas". --- */
.cita {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1px solid var(--linea);
  border-radius: var(--r);
  margin-bottom: 10px;
  transition: border-color .2s, transform .2s var(--v2-spring);
}
.cita:hover {
  border-color: var(--lavanda);
  transform: translateX(3px);
}
.cita__fecha {
  text-align: center;
  min-width: 58px;
  flex: none;
}
.cita__fecha .d {
  font-family: var(--fuente-titulo);
  font-weight: 700;
  font-size: 1.35rem;
  color: var(--violeta);
  line-height: 1;
}
.cita__fecha .m {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--tinta-3);
  font-weight: 700;
}
.cita__b {
  flex: 1;
  min-width: 0;
}
/* display:block a propósito: un hijo de flex no recorta con ellipsis
   (queda en caja anónima). Ya nos costó una vez. */
.cita__b b {
  display: block;
  font-size: .98rem;
}
.cita__b span {
  display: block;
  font-size: .85rem;
  color: var(--tinta-2);
}
.cita__ac {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

/* --- Chips de ESTADO. Autónomos: se usan sin .chip (ver nota de arriba). --- */
.chip--conf,
.chip--hecha {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: .72rem;
  font-weight: 700;
  padding: 4px 9px;
  border-radius: 999px;
  white-space: nowrap;
  box-shadow: none;
}
.chip--conf {
  background: var(--menta-claro);
  color: #0c6b58;
}
.chip--hecha {
  background: var(--violeta-claro);
  color: var(--violeta);
}
.chip--conf svg,
.chip--hecha svg {
  width: 12px;
  height: 12px;
}

/* --- Mi ficha clínica --- */
.ficha-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.dato-card {
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 16px;
  background: var(--bg-2);
  min-width: 0;
}
.dato-card .k {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--violeta);
  margin-bottom: 7px;
}
.dato-card .k svg {
  width: 15px;
  height: 15px;
  flex: none;
}
.dato-card .v {
  font-size: .95rem;
  color: var(--tinta);
  overflow-wrap: anywhere;
}
/* Envoltorio de etiquetas dentro de un .dato-card (especialidades hoy;
   alergias/antecedentes el día que el API se los exponga a la paciente). */
.antec {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.ficha-nota {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-top: 16px;
  padding: 13px 16px;
  border-radius: var(--r);
  background: var(--menta-claro);
  border: 1px solid rgba(15, 168, 150, .28);
}
.ficha-nota svg {
  width: 20px;
  height: 20px;
  color: var(--menta);
  flex: none;
  margin-top: 1px;
}
.ficha-nota p {
  font-size: .88rem;
  color: #0c6b58;
  margin: 0;
}

/* --- Mis consentimientos --- */
.cons-item {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 14px 16px;
  margin-bottom: 10px;
}
.cons-item__ic {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--menta-claro);
  color: var(--menta);
  display: grid;
  place-items: center;
  flex: none;
}
.cons-item__ic svg {
  width: 20px;
  height: 20px;
}
/* No aceptado: gris, NO rojo. Rechazar un consentimiento opcional es un
   derecho de la paciente, no un error suyo. */
.cons-item__ic--off {
  background: var(--violeta-claro);
  color: var(--tinta-3);
}
.cons-item__b {
  flex: 1;
  min-width: 0;
}
.cons-item__b b {
  display: block;
  font-size: .94rem;
}
.cons-item__d {
  font-size: .86rem;
  color: var(--tinta-2);
  margin-top: 3px;
}
.cons-item__m {
  display: block;
  font-size: .8rem;
  color: var(--tinta-3);
  margin-top: 5px;
}
.cons-item__est {
  flex: none;
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
/* Los .tag de acá ("Obligatorio"/"Opcional"/"No aceptado") arrastran
   `margin: 0 5px 5px 0` de estilos.css:520, que es de cuando el .tag vivía
   suelto en un párrafo y necesitaba separarse de sus hermanos a mano.
   Dentro de esta columna flex el margen sobra y estorba:
     · el margin-right de 5px los despega del borde derecho (medido: 5.0px)
       y los desalinea contra todo lo demás del panel;
     · el margin-bottom de 5px se SUMA al `gap: 6px` → 11px entre etiquetas.
   Se anula solo acá (0,2,0 → gana a .tag sin depender del orden de hojas).
   NO se toca `.tag` global: la usan el flujo de reserva y el superadmin,
   donde ese margen sí hace su trabajo. */
.cons-item__est .tag {
  margin: 0;
}
.cons-pie {
  font-size: .84rem;
  color: var(--tinta-2);
  line-height: 1.6;
  margin-top: 16px;
}

/* --- Mis documentos ---
   (.docs-sec-tit ya no se define: los dos encabezados de sección pasaron a
   .panel__h, así que su CSS habría nacido muerto.) */
.docs-sec-vacio {
  color: var(--tinta-2);
  font-size: .9rem;
  padding: 14px 16px;
  border: 1px dashed var(--linea);
  border-radius: var(--r);
  margin: 0;
}
/* El mockup lista los documentos en vertical (se leen mejor: título, fecha,
   folio y acción en la misma línea). estilos.css:598 los pone en grid
   auto-fill de 280px. .docs-grid y .doc-card solo las usa paciente.js, así
   que este override no alcanza a ningún otro portal. */
.docs-grid,
.docs-mios {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}
/* Nombre del archivo: cortar donde sea antes que romper la caja.
   El <b> lo llena `esc(a.nombre_original)` (paciente.js:940), o sea el nombre
   REAL del archivo que subió la paciente — dato que no controlamos. Un
   "ecografia_transvaginal_control_anual_2026_definitivo_v2.pdf" no tiene NI UN
   espacio donde cortar, así que el navegador lo trata como una sola palabra y
   se sale de la tarjeta. Medido a 560px y a 375px: texto 582px dentro de una
   caja de 523px → 59px afuera. No se veía como bug porque
   `html,body{overflow-x:hidden}` (estilos.css:94) lo tapa: el nombre queda
   cortado sin puntos suspensivos y la fila descuadrada.
   `anywhere` (no `break-word`) porque también encoge la caja al calcular el
   min-content: es lo que ya usa `.dato-card .v` (acá arriba) para lo mismo.
   `.doc-card__txt` ya trae `min-width: 0` (estilos.css:602), que es la otra
   mitad de la receta en un contenedor flex. */
.doc-card__txt b {
  overflow-wrap: anywhere;
}

.doc-card__ic--celeste {
  background: var(--celeste-claro);
  color: #0b5e96;
}
.doc-card__ic--menta {
  background: var(--menta-claro);
  color: #0c6b58;
}
.doc-card__ic--durazno {
  background: var(--durazno-claro);
  color: #8a6a00;
}
.doc-card__ac {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  flex: none;
}
.docs-subir {
  margin-top: 22px;
  padding: 18px;
  border: 1px dashed var(--lavanda);
  border-radius: var(--r);
  background: var(--bg-2);
}
.docs-subir > b {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--fuente-titulo);
  font-size: 1rem;
}
.docs-subir--off {
  text-align: center;
  border-color: var(--linea);
}
.docs-subir--off > svg {
  color: var(--lavanda);
  margin: 0 auto 8px;
}
.docs-subir--off p {
  color: var(--tinta-2);
  font-size: .9rem;
  margin: 0 0 10px;
}

/* Colapso propio de estas vistas (clases nuevas: no pisan breakpoints vivos). */
@media (max-width: 980px) {
  .ficha-grid {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 560px) {
  .cita {
    flex-wrap: wrap;
  }
  .cita__ac {
    width: 100%;
  }
  .doc-card {
    flex-wrap: wrap;
  }
  .doc-card__ac {
    width: 100%;
  }
  /* 🔴 REGRESIÓN QUE PILLÓ RENATA (16-jul), y la causa vale documentarla:
     `estilos.css:750` trae `.doc-card .btn { flex:1 1 100% }` DESDE HACE MESES,
     dentro de este mismo @media. Nunca aplicaba, porque los botones de esta
     vista eran `.tag--btn` dentro de `.doc-item`. Al pasar el JS a `.doc-card` +
     `.btn`, esa regla vieja EMPEZÓ A APLICAR donde jamás lo había hecho: el
     botón de ELIMINAR (un ícono) se estiraba a 448px, apilado bajo "Ver".
     🔴 LECCIÓN: renombrar una clase puede ACTIVAR reglas ajenas dormidas. No
     basta con buscar colisiones de la clase nueva; hay que ver qué reglas
     EXISTENTES empiezan a alcanzar el elemento.

     Los DOS botones de texto ("Descargar" en la sección de documentos, "Ver" en
     la de exámenes) SÍ deben llenar la fila en móvil: así se ve hoy en vivo y
     así lo pide el mockup aprobado (`mock-paciente-cuenta.html:211` →
     `.doc-item__ac .btn{flex:1}`). El único que NO debe estirarse es el
     destructivo: es un ícono solo, y un basurero rojo de media fila invita al
     accidente. El mockup no tuvo que resolver esto porque ahí los dos botones
     eran de texto.
     `[data-miodel]` es un discriminador seguro: ese atributo YA es contrato (el
     JS lo lee para saber qué examen borrar), así que no se renombra al pasar.
     Especificidad: (0,2,0) y (0,3,0) → ambas ≥ que la de estilos.css y cargan
     después. Scopeadas al @media para no tocar el desktop. */
  .doc-card__ac .btn {
    flex: 1;
    margin-top: 0;
  }
  .doc-card__ac .btn[data-miodel] {
    flex: 0 0 auto;
  }
}
@media (prefers-reduced-motion: reduce) {
  .cita:hover {
    transform: none;
  }
}

/* ============================================================
   12) MI CUENTA (PACIENTE) — HERO DE LA PRÓXIMA CONSULTA
       (Mateo, 16-jul-2026 · Tanda 2 de 2)
       Referencia: propuestas-portal/mock-paciente-cuenta.html (.hero-cita).
       Pinta SOLO la primera cita de "Próximas consultas". Las siguientes
       siguen siendo .cita-cuenta y no se tocan.

   QUÉ REGLAS EXISTENTES ALCANZAN ESTE MARKUP (auditado antes de escribir,
   que es justo lo que nos faltó con .doc-card)
   ------------------------------------------------------------
   El hero es `class="panel js-rev hero-cita cita-prox-destacada"`, así que
   hereda a propósito:
     · .panel (estilos.css:273 + acá:153) -> fondo blanco, radio, sombra,
       borde, padding 22px. Se conserva como RED DE SEGURIDAD: si se cayera
       el <link> de esta hoja, el hero degrada a tarjeta legible en vez de a
       texto pelado. Los 5 deltas (background/border/box-shadow/padding/
       display) se repintan abajo; ganan por ORDEN (misma especificidad 0,1,0
       y esta hoja va después). Por eso este bloque DEBE quedar al final.
     · .js-rev (estilos.css:707) -> reveal. Intacto: sigue siendo 1 hijo por
       cita, así que los nth-child(2..5) de la lista no se corren.
     · #dash-citas > .panel (acá:179) NO lo alcanza: eso es del portal médico;
       el paciente inyecta en #cta-vista (index.html:298).
     · .cita-prox-destacada no tiene CSS en ninguna hoja (verificado en todo
       el repo). Se conserva igual: cuesta cero y es un hook.
   Y REUSA a propósito, por descendencia de clase (no exigen a .cita-cuenta
   como padre, así que funcionan sueltas):
     · .cita-cuenta__datos (estilos.css:586-588) + su colapso a 1 columna del
       @media 560 (:747). Se reusa EN VEZ de reinventarla: su responsive ya
       está probado en vivo. Mismo criterio para .cita-cuenta__estado (:584),
       .pill--celeste (:267) y .med-card__foto (:256).
   Y EVITA a propósito:
     · .cita-cuenta__acc -> arrastra `.btn{flex:1;min-width:150px}` (:590) y
       `min-width:100%` del @media 560 (:748). En el hero los botones van a
       ancho natural, así que el markup usa .hero-cita__ac (clase nueva) y el
       apilado móvil se declara acá abajo. Sin clase compartida no hay regla
       dormida que despertar.

   VARIABLES: el mockup es autocontenido y usa tokens que NO EXISTEN en el
   portal vivo. Verificadas una por una contra el :root de estilos.css:
     · --f-titulo  -> NO EXISTE. El vivo es --fuente-titulo (Quicksand).
     · --ease / --spring -> NO EXISTEN. Acá son --v2-ease / --v2-spring.
     · --grad-primario / --sombra-color / --violeta-claro / --menta / --r-lg
       sí existen y se usan tal cual.
   Copiar el mockup literal habría dejado el hero sin Quicksand y sin easing,
   fallando en silencio (una var() inexistente no avisa: invalida la
   propiedad y se hereda).

   DESVIACIONES DELIBERADAS DEL MOCKUP (documentadas, no olvidos)
     · El punto .live que pulsa NO se implementa: diría "en vivo" aunque la
       consulta sea en 3 días (el texto de la ventana se calcula UNA vez al
       pintar; el countdown vivo es feature aparte, fuera del re-skin).
     · El avatar NO se oculta en móvil (el mockup lo esconde a ≤980px): hoy
       la foto del médico SÍ se ve en móvil y esconderla sería una regresión.
       Baja a 64px, que es su tamaño de siempre.
   ============================================================ */
.hero-cita {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px 20px;
  align-items: center;
  padding: 24px;
  border: 1.5px solid var(--violeta-claro);
  border-radius: var(--r-lg);
  background: linear-gradient(135deg, #ede9ff 0%, #fff 62%);
  box-shadow: var(--sombra-sm);
  position: relative;
  overflow: hidden;
  margin-bottom: 16px;
}
/* Halo decorativo del mockup. aria-hidden por naturaleza (::after no entra
   al árbol de accesibilidad) y pointer-events:none para no comerse clics
   del botón de unirse, que cae justo bajo su esquina. */
.hero-cita::after {
  content: "";
  position: absolute;
  right: -40px;
  top: -40px;
  width: 190px;
  height: 190px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(122, 110, 224, .16), transparent 70%);
  pointer-events: none;
}
.hero-cita__l {
  position: relative;
  z-index: 2;
  min-width: 0;
}
.hero-cita__tag {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--fuente-titulo);
  font-weight: 700;
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--violeta);
}
.hero-cita__tag svg {
  width: 14px;
  height: 14px;
  flex: none;
}
.hero-cita__med {
  font-family: var(--fuente-titulo);
  font-weight: 700;
  font-size: 1.35rem;
  margin-top: 8px;
  line-height: 1.25;
}
.hero-cita__meta {
  color: var(--tinta-2);
  font-size: .94rem;
  margin-top: 2px;
}
/* El JS manda font-weight, margin y color INLINE (ganan siempre, no se
   pelean). Acá solo cuerpo y tamaño, que el inline no trae. */
.hero-cita__cd {
  font-family: var(--fuente-titulo);
  font-size: 1.2rem;
}
.hero-cita__ac {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  position: relative;
  z-index: 2;
}
/* Columna del avatar. */
.hero-cita__r {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}
/* El avatar llega desde pintarFotos() con class="med-card__foto" (64px), que
   es CONTRATO. Se agranda desde el contenedor: (0,2,0) le gana a (0,1,0) sin
   depender del orden de hojas. Sirve igual para el <img> y para el <span> de
   iniciales del fallback. */
.hero-cita__r .med-card__foto {
  width: 96px;
  height: 96px;
  border-radius: 26px;
  font-size: 2.1rem;
  background: var(--grad-primario);
  color: #fff;
  box-shadow: var(--sombra-color);
}
/* Pie a todo el ancho: reserva + datos + exámenes. */
.hero-cita__pie {
  grid-column: 1 / -1;
  position: relative;
  z-index: 2;
  min-width: 0;
  margin-top: 4px;
  padding-top: 14px;
  border-top: 1px solid var(--linea);
}
.hero-cita__pie > .pill {
  margin-bottom: 12px;
}
.hero-cita__pie .cita-cuenta__datos {
  margin-bottom: 0;
}
/* :not(:empty) porque pintarExamenes() no pinta nada si no encuentra la cita:
   sin esto quedaría un margen fantasma bajo los datos. */
.hero-cita__pie .ex-wrap:not(:empty) {
  margin-top: 12px;
}

/* --- Responsive. Breakpoints propios: .hero-cita* son clases nuevas, así que
       nadie más las declara y no hay @media ajeno al que ganarle por orden.
       Se alinean igual con los cortes vivos (900 / 560). --- */
@media (max-width: 900px) {
  .hero-cita {
    grid-template-columns: 1fr;
    justify-items: start;
  }
  /* El avatar pasa arriba del texto y vuelve a su tamaño de siempre, en fila
     con el estado. Se mantiene visible: ver desviación documentada arriba. */
  .hero-cita__r {
    grid-row: 1;
    flex-direction: row;
    gap: 12px;
    margin-bottom: 4px;
  }
  .hero-cita__r .med-card__foto {
    width: 64px;
    height: 64px;
    border-radius: 18px;
    font-size: 1.2rem;
  }
}
@media (max-width: 560px) {
  .hero-cita {
    padding: 18px;
  }
  /* Botones a ancho completo, como el resto del portal en móvil. El mínimo
     táctil lo garantiza .btn (min-height:46px, acá:322): el hero NO usa
     btn--sm justamente para no bajar a 40px. */
  .hero-cita__ac .btn {
    flex: 1 1 100%;
    justify-content: center;
  }
  .hero-cita__med {
    font-size: 1.2rem;
  }
}
/* Sin guarda de prefers-reduced-motion: el hero no anima nada por su cuenta
   (el reveal lo pone .js-rev, que estilos.css:754 ya neutraliza). */

/* ============================================================
   RE-SKIN CALENDARIO DE RESERVA DEL PACIENTE (mock-paciente-reserva-v2.html)
   ------------------------------------------------------------
   ADITIVO. Anclado a #agenda-dias / #agenda-slots: esos IDs SOLO existen en
   index.html (portal SPA), no en la agenda del MÉDICO (medico.js comparte las
   clases .ag-* pero NO estos wrappers) -> el médico conserva su aspecto.
   NO se toca agenda-cal.js ni estilos.css. Reemplaza el override de "colores
   fuertes" de estilos.css:990-1039 (teal/rojo sólidos): portal-v2.css carga
   DESPUÉS y, a igual especificidad, gana. Donde estilos.css sube especificidad
   (:hover:not()), acá se replica la MISMA para ganar por orden de fuente.
   Look aprobado: calendario suave de puntos, día seleccionado en gradiente.
   ============================================================ */

/* --- Celda base: cuadrada, contenido centrado, borde neutro --- */
#agenda-dias .ag-dia{
  aspect-ratio:1;min-height:0;padding:0;
  display:grid;place-items:center;
  border-radius:12px;border:1.5px solid transparent;background:var(--bg);
  position:relative;               /* ancla el punto ::after de --libre */
}
/* Celdas de relleno (offset del 1er día): invisibles. Mi regla base les puso
   background:var(--bg); acá lo revierto para que no se vean como cuadros. */
#agenda-dias .ag-dia--off{background:transparent;border-color:transparent}

/* Número del día. Base = --tinta; se ajusta por estado más abajo. */
#agenda-dias .ag-dia-n{color:var(--tinta);font-weight:700}

/* "N horas" / "sin cupo": se OCULTA visualmente pero queda para lectores de
   pantalla (sr-only). NO display:none, para no perder la info accesible. */
#agenda-dias .ag-dia-i{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* --- Día con horas (libre): neutro + punto menta abajo, hover lavanda --- */
#agenda-dias .ag-dia--libre{background:var(--bg);border-color:transparent}
#agenda-dias .ag-dia--libre .ag-dia-n{color:var(--tinta)}
#agenda-dias .ag-dia--libre::after{
  content:"";position:absolute;bottom:6px;left:50%;transform:translateX(-50%);
  width:5px;height:5px;border-radius:50%;background:var(--menta);
}
/* Misma especificidad que estilos.css:1014 (:hover:not(.ag-dia--off)) para
   ganarle su fondo teal por orden de fuente. */
#agenda-dias .ag-dia--libre:hover:not(.ag-dia--off){background:var(--bg);border-color:var(--lavanda)}

/* --- Día sin cupo / sin atención: apagados, no seleccionables --- */
#agenda-dias .ag-dia--lleno{background:var(--bg);border-color:transparent;opacity:.4;cursor:default}
#agenda-dias .ag-dia--lleno .ag-dia-n{color:var(--tinta)}
#agenda-dias .ag-dia--vacio{background:var(--bg);border-color:transparent;opacity:.4;cursor:default}
#agenda-dias .ag-dia--vacio .ag-dia-n{color:var(--tinta-3)}

/* --- Hoy: anillo violeta interior (reemplaza el doble anillo de estilos.css:1028) --- */
#agenda-dias .ag-dia--hoy{box-shadow:0 0 0 2px var(--violeta) inset}

/* --- Seleccionado: gradiente primario, texto y punto blancos. DESPUÉS de
   --libre para ganarle el fondo a igual especificidad. Quita el outline fuerte
   de estilos.css:1027 (el foco de teclado sigue via :focus-visible). --- */
#agenda-dias .ag-dia--sel{background:var(--grad-primario);border-color:transparent;outline:none}
#agenda-dias .ag-dia--sel .ag-dia-n{color:#fff}
#agenda-dias .ag-dia--sel.ag-dia--libre::after{background:#fff}

/* --- Horas del día (slots) en #agenda-slots: chip contorneado, hover menta,
   seleccionado en gradiente menta. --grad-menta existe en estilos.css:57; se
   deja fallback literal por si el token faltara. --- */
#agenda-slots .slot{
  border:1.5px solid var(--linea);background:var(--bg);border-radius:12px;
  color:var(--tinta);font-weight:600;
}
#agenda-slots .slot:hover:not(.is-on){border-color:var(--menta);color:var(--menta);background:var(--bg)}
/* Contraste AA (Renata): --grad-menta (#0fa896->#3b8fd4) con texto blanco daba
   ~2.9-3.5:1, bajo AA 4.5. Se usa el teal sólido #0b7266 del sistema (estilos.css
   :1005, semántica "menta = hay horas"): blanco sobre #0b7266 = 5.81:1 ✓ AA. Se
   mantiene texto blanco e identidad menta/teal. NO se toca el día seleccionado. */
#agenda-slots .slot.is-on{
  background:#0b7266;
  color:#fff;border-color:transparent;box-shadow:0 10px 24px rgba(15,168,150,.25);
}

/* ============================================================
   RE-SKIN AGENDA DEL PROPIO MÉDICO (mock-medico-agenda-v2.html) — Fase 3
   ------------------------------------------------------------
   ADITIVO y CSS-ONLY. Anclado a #agenda-medico: ese ID SOLO existe en
   medico.html (medico.js:pintarMiAgenda / agSeleccionarDia lo pueblan). El
   paciente usa las MISMAS clases .ag-*/.slot pero bajo #agenda-dias/
   #agenda-slots -> queda intacto (sus overrides viven arriba, líneas ~1493).
   NO se toca medico.js ni estilos.css. medico.js emite exactamente:
     · días  <button class="ag-dia ag-dia--libre|--lleno|--vacio|--off
              [ag-dia--hoy][ag-dia--sel]"><span class=ag-dia-n>N</span>
              [<span class=ag-dia-i>info</span>]</button>
     · slots <button class="slot is-on|is-off|is-res" [disabled]>HH:MM</button>
       (contenido = SOLO la hora; el label de estado y el candado se pintan
        con ::after / ::before, por eso NO hace falta tocar el JS.)
   Diferencia con el paciente: acá el médico SÍ necesita ver el conteo del día
   (.ag-dia-i "3 libres"/"2 tomadas"), así que NO se oculta.
   Tokens vivos de estilos.css; teal literal #0b7266 (no hay --teal), igual que
   en el bloque del paciente. A igual especificidad gana por orden de fuente.
   ============================================================ */

/* ---------- Grilla del mes: días cuadrados, Quicksand ---------- */
#agenda-medico .ag-dia{
  aspect-ratio:1;min-height:0;padding:8px 9px;
  display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;
  gap:2px;position:relative;
  border-radius:14px;border:1.5px solid var(--linea);background:var(--bg);
  font-family:var(--fuente-titulo);
  transition:background .2s,border-color .2s,transform .2s;
}
#agenda-medico .ag-dia:hover:not(.ag-dia--off){border-color:var(--lavanda);transform:translateY(-1px);box-shadow:none}
#agenda-medico .ag-dia--off{background:transparent;border-color:transparent;cursor:default}
#agenda-medico .ag-dia-n{font-weight:700;font-size:1rem;color:var(--tinta);line-height:1}
#agenda-medico .ag-dia-i{margin-top:auto;font-family:var(--fuente);font-weight:600;font-size:.66rem;line-height:1.15}

/* ------------------------------------------------------------------
   COLORES INVERTIDOS (20-jul-2026) — se leen desde la médica, no desde la paciente.
   Antes: verde = "quedan horas libres". Para una médica eso es la MALA noticia
   (nadie la agendó) y se le pintaba con el color del éxito.
   Ahora: verde = día completo · ámbar = quedan horas · rojo suave = nadie agendó.
   🔴 El calendario de la PACIENTE (#agenda-dias, estilos.css:1005+) NO se toca:
   allá verde="hay horas" es correcto —ella busca un hueco— y sigue igual.
   ------------------------------------------------------------------ */
/* Día COMPLETO (todas tomadas): menta = objetivo cumplido */
#agenda-medico .ag-dia--lleno{background:var(--menta-claro);border-color:rgba(15,168,150,.3)}
#agenda-medico .ag-dia--lleno .ag-dia-i{color:#0b7266}
#agenda-medico .ag-dia--lleno::after{
  content:"";position:absolute;top:9px;right:9px;
  width:7px;height:7px;border-radius:50%;background:var(--menta);
}
/* Día PARCIAL (le tomaron algunas, quedan huecos): ámbar = atención */
#agenda-medico .ag-dia--libre{background:var(--amarillo-claro);border-color:rgba(212,135,10,.3)}
#agenda-medico .ag-dia--libre .ag-dia-i{color:#8f5e06}
#agenda-medico .ag-dia--libre::after{
  content:"";position:absolute;top:9px;right:9px;
  width:7px;height:7px;border-radius:50%;background:var(--amarillo);
}
/* Día que NADIE agendó: rojo suave. Clase nueva — no existe en estilos.css, así
   que se define entera acá (fondo, número y punto). */
#agenda-medico .ag-dia--nadie{background:#fdecef;border-color:rgba(190,18,60,.28)}
#agenda-medico .ag-dia--nadie .ag-dia-n{color:#8c1233}
#agenda-medico .ag-dia--nadie .ag-dia-i{color:#a8213f}
#agenda-medico .ag-dia--nadie::after{
  content:"";position:absolute;top:9px;right:9px;
  width:7px;height:7px;border-radius:50%;background:#be123c;
}
/* Día sin horario cargado: borde punteado, apagado */
#agenda-medico .ag-dia--vacio{background:var(--bg-2);border-style:dashed;border-color:var(--linea)}
#agenda-medico .ag-dia--vacio .ag-dia-n{color:var(--tinta-3)}
#agenda-medico .ag-dia--vacio .ag-dia-i{color:var(--tinta-3)}
/* Hoy: anillo violeta */
#agenda-medico .ag-dia--hoy{box-shadow:0 0 0 2px var(--violeta) inset}
/* Día seleccionado: gradiente primario, texto/punto en blanco (reemplaza el
   outline fuerte de estilos.css:966). Va DESPUÉS de --libre/--lleno para
   ganarles el fondo a igual especificidad. */
#agenda-medico .ag-dia--sel{background:var(--grad-primario);border-color:transparent;box-shadow:var(--sombra-color)}
#agenda-medico .ag-dia--sel .ag-dia-n{color:#fff}
#agenda-medico .ag-dia--sel .ag-dia-i{color:rgba(255,255,255,.9)}
#agenda-medico .ag-dia--sel.ag-dia--libre::after,
#agenda-medico .ag-dia--sel.ag-dia--nadie::after,
#agenda-medico .ag-dia--sel.ag-dia--lleno::after{background:#fff}
/* El día seleccionado pinta su número en blanco; --nadie lo tenía en granate. */
#agenda-medico .ag-dia--sel.ag-dia--nadie .ag-dia-n{color:#fff}
#agenda-medico .ag-dia--sel.ag-dia--nadie .ag-dia-i{color:rgba(255,255,255,.9)}

/* ---------- Leyenda de estados de día ---------- */
#agenda-medico .ag-leyenda{
  gap:12px 20px;margin:14px 0 18px;padding:14px 0;
  border-top:1px solid var(--linea);border-bottom:1px solid var(--linea);
}
#agenda-medico .ag-lg{width:22px;height:22px;border-radius:7px;position:relative;border:1.5px solid transparent}
/* Muestras de la leyenda: calzan con los colores invertidos de arriba. */
#agenda-medico .ag-lg--lleno{background:var(--menta-claro);border-color:rgba(15,168,150,.35)}
#agenda-medico .ag-lg--lleno::after{
  content:"";position:absolute;top:4px;right:4px;
  width:5px;height:5px;border-radius:50%;background:var(--menta);
}
#agenda-medico .ag-lg--libre{background:var(--amarillo-claro);border-color:rgba(212,135,10,.3)}
#agenda-medico .ag-lg--libre::after{
  content:"";position:absolute;top:4px;right:4px;
  width:5px;height:5px;border-radius:50%;background:var(--amarillo);
}
#agenda-medico .ag-lg--nadie{background:#fdecef;border-color:rgba(190,18,60,.3)}
#agenda-medico .ag-lg--nadie::after{
  content:"";position:absolute;top:4px;right:4px;
  width:5px;height:5px;border-radius:50%;background:#be123c;
}
#agenda-medico .ag-lg--vacio{background:var(--bg-2);border:1.5px dashed var(--linea)}

/* ---------- Detalle del día (apilado bajo el calendario) ---------- */
#agenda-medico .ag-det-sub{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--fuente-titulo);font-weight:700;font-size:.78rem;
  letter-spacing:.03em;text-transform:uppercase;color:var(--violeta);
}

/* ---------- Chips de hora: 3 estados por COLOR + FORMA ----------
   El botón solo trae la hora como texto. El label de estado se agrega con
   ::after (content) y el punto/candado con ::before. Sin tocar el JS. */
#agenda-medico .slots{display:flex;gap:10px;flex-wrap:wrap;grid-template-columns:none}
#agenda-medico .slot{
  position:relative;display:inline-flex;flex-direction:column;
  align-items:flex-start;justify-content:center;gap:3px;
  min-width:96px;padding:10px 14px 9px;border-radius:14px;
  border:1.5px solid var(--linea);background:var(--blanco);
  font-family:var(--fuente-titulo);font-weight:700;font-size:.98rem;
  color:var(--tinta);text-align:left;text-decoration:none;
  transition:border-color .2s,background .2s,transform .2s,box-shadow .2s;
}
/* Label de estado (2ª línea). El texto lo pone cada estado más abajo. */
#agenda-medico .slot::after{
  font-family:var(--fuente);font-weight:600;font-size:.66rem;
  display:inline-flex;align-items:center;gap:5px;
}
/* Abierta (disponible para pacientes): menta + punto menta + "Abierta" */
#agenda-medico .slot.is-on{background:var(--menta-claro);border-color:rgba(15,168,150,.5);color:var(--tinta)}
#agenda-medico .slot.is-on::before{
  content:"";width:7px;height:7px;border-radius:50%;background:var(--menta);
  position:absolute;top:11px;right:12px;
}
#agenda-medico .slot.is-on::after{content:"Abierta";color:#0b7266}
#agenda-medico .slot.is-on:hover{transform:translateY(-1px);box-shadow:0 8px 20px rgba(15,168,150,.18)}
/* Cerrada por el médico: contorno punteado gris + "Cerrada" (sin line-through) */
#agenda-medico .slot.is-off{background:var(--bg-2);border-style:dashed;border-color:var(--linea);color:var(--tinta-2);text-decoration:none}
#agenda-medico .slot.is-off::after{content:"Cerrada";color:var(--tinta-3)}
#agenda-medico .slot.is-off:hover{transform:translateY(-1px);border-color:var(--lavanda);color:var(--violeta)}
/* Reservada por una paciente: violeta + CANDADO (::before) + "Reservada",
   bloqueada (el JS ya le pone [disabled]). */
#agenda-medico .slot.is-res{
  background:var(--violeta-claro);border-color:rgba(91,79,207,.4);color:var(--violeta);
  cursor:not-allowed;padding-right:34px;
}
#agenda-medico .slot.is-res::before{
  content:"";position:absolute;top:9px;right:11px;width:15px;height:15px;
  background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235b4fcf' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='11' width='16' height='10' rx='2'/%3E%3Cpath d='M8 11V8a4 4 0 018 0v3'/%3E%3C/svg%3E");
}
#agenda-medico .slot.is-res::after{content:"Reservada";color:var(--violeta)}

/* ---------- Pacientes agendados + tabla "Próximas horas tomadas" ---------- */
#agenda-medico .ag-pac{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  background:var(--blanco);border:1px solid var(--linea);border-radius:14px;
  padding:11px 14px;
}
#agenda-medico .ag-est{border-radius:999px;padding:5px 11px}
#agenda-medico .ag-prox .tabla{border:1px solid var(--linea);border-radius:var(--r-lg);overflow:hidden}
#agenda-medico .ag-prox .tabla thead th{
  font-family:var(--fuente-titulo);font-weight:700;font-size:.74rem;
  letter-spacing:.02em;text-transform:uppercase;color:var(--tinta-3);
  background:var(--bg);
}

/* ============================================================
   16) MENÚ ARRIBA — portal del médico (20-jul-2026)
   medico.html usa ahora `class="dash dash--top"`. La mecánica horizontal
   base ya vive en estilos.css:406-412 (display:block, side en flex,
   nav en fila, nav-item de ancho automático); acá va SOLO el afinado
   visual para que la barra no se vea como el sidebar aplastado.
   Motivo del cambio: recuperar los 248 px de ancho que el sidebar le
   quitaba a la sala en vivo (18% de un portátil de 1366).
   🔴 NO se toca el contrato del JS: .nav-item, .is-on, data-nav y los IDs
   nv-* / dash-perfil siguen exactamente igual.
   ============================================================ */

/* El grid de 248px de la sección 2 vive dentro de @media(min-width:901px) y
   solo fija columnas —no `display`—, así que el display:block de
   .dash--top manda. Se declara igual, explícito, para que no dependa del
   orden de fuente si mañana alguien toca la sección 2. */
.dash--top { display: block; }

/* La barra: menos alta que el sidebar y pegada arriba al hacer scroll.
   estilos.css:407 ya la pasa a position:static; acá se sube a sticky para
   que el menú siga a mano en pantallas largas (agenda, pacientes). */
.dash--top .dash__side {
  position: sticky;
  top: 84px;
  z-index: 20;
  padding: 10px 14px;
  gap: 14px;
  background: var(--blanco);
}

/* Perfil en línea: foto chica + nombre/especialidad apilados al lado.
   En vertical la foto era de 66px y el bloque iba centrado; acá eso
   dispararía el alto de toda la barra. */
.dash--top .dash__perfil {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px 0 0;
  margin: 0;
  text-align: left;
  flex-wrap: nowrap;
}
.dash--top .dash__perfil .perfil__foto {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  margin: 0;
  flex: none;
}
/* El nombre y la especialidad son dos <div> sueltos que el JS inyecta
   (medico.js:83-85). Sin envoltorio propio, se les quita el margin que
   traían del layout vertical y se compactan. */
.dash--top .dash__perfil > div { margin: 0 !important; line-height: 1.25; }
.dash--top .dash__perfil .med-card__esp { font-size: .74rem; }
/* "Cambiar foto" pasa a ser secundario: en la barra no puede competir con
   la navegación. Se mantiene accesible (no display:none). */
.dash--top .dash__perfil .btn {
  margin-top: 0 !important;
  padding: 4px 8px;
  font-size: .72rem;
}

/* Ítems del menú en fila. El activo conserva su gradiente de la sección 3. */
.dash--top .dash__side nav { gap: 4px; }
.dash--top .nav-item {
  padding: 8px 12px;
  border-radius: 11px;
  font-size: .88rem;
  white-space: nowrap;
}
.dash--top .nav-item svg { width: 17px; height: 17px; }

/* "Cerrar sesión" empujado al extremo derecho: es una salida, no una
   sección más, y así deja de estar pegado a "Seguridad". */
.dash--top .dash__side nav #nv-salir { margin-left: auto; }

/* Angosto: la barra se apila (estilos.css:412 ya lo hace) y el nav pasa a
   deslizarse de lado en vez de romper en varias filas altas. */
@media (max-width: 900px) {
  .dash--top .dash__side { position: static; }
  .dash--top .dash__side nav { flex-wrap: nowrap; overflow-x: auto; }
  .dash--top .dash__side nav #nv-salir { margin-left: 0; }
}

/* ============================================================
   17) BARRA DE CONTEXTO DE LA PACIENTE — #pac-ctx (20-jul-2026)
   Una franja arriba de la sala con identidad + antecedentes + MRS +
   última consulta. Reemplaza a .id-bar (bajo el video) y a la cabecera
   que #ses-ficha repetía: el mismo dato se pintaba 3 veces.
   Vive fuera de .sesion-sala, así que no entra en el grid de la sala
   ni en el recálculo de alturas del modo jitsi.
   ============================================================ */
.pac-ctx {
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  background: var(--blanco);
  padding: 12px 16px;
  margin-bottom: 14px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  /* Pegada bajo la barra de menú (que es sticky en top:84px y mide ~60px). */
  position: sticky;
  top: 152px;
  z-index: 15;   /* < 60/61 del hv-drawer: el cajón siempre la tapa */
  box-shadow: var(--sombra-sm);
}

/* --- Fila 1: identidad --- */
.pac-ctx__id { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.pac-ctx__ava {
  width: 40px; height: 40px; border-radius: 13px; flex: none;
  display: grid; place-items: center;
  background: var(--grad-primario); color: #fff;
  font-family: var(--fuente-titulo); font-weight: 700; font-size: .85rem;
}
.pac-ctx__id > div { min-width: 0; line-height: 1.25; }
.pac-ctx__id b { display: block; font-size: 1.02rem; }
.pac-ctx__id span { font-size: .82rem; color: var(--tinta-2); }

.pac-ctx__sello {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .74rem; font-weight: 700;
  padding: 4px 11px; border-radius: 999px;
}
.pac-ctx__sello--ok { background: var(--menta-claro); color: #0b7266; }
.pac-ctx__sello--pend { background: var(--amarillo-claro, #fff5d6); color: #8a6a00; }

/* --- Fila 2: chips de lo que la paciente arrastra --- */
.pac-ctx__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.pac-ctx__chip {
  font-size: .76rem; font-weight: 600;
  padding: 4px 11px; border-radius: 999px;
  border: 1px solid transparent;
  max-width: 100%; overflow-wrap: anywhere;
}
/* Alergias en rojo: es el dato que puede matar a alguien si se pasa por alto. */
.pac-ctx__chip--al { background: #fdecef; color: #8c1233; }
.pac-ctx__chip--cr { background: var(--amarillo-claro, #fff5d6); color: #8a6a00; }
.pac-ctx__chip--me { background: var(--violeta-claro); color: var(--violeta); }
.pac-ctx__chip--mrs { background: var(--menta-claro); color: #0b7266; }
.pac-ctx__chip--vacio {
  background: transparent; border-color: var(--linea);
  color: var(--tinta-3); font-weight: 500;
}

/* --- Fila 3: última consulta + puerta al historial --- */
.pac-ctx__pie {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  border-top: 1px solid var(--linea); padding-top: 9px;
}
.pac-ctx__ultima { font-size: .82rem; color: var(--tinta-2); min-width: 0; flex: 1; }
.pac-ctx__pie .btn { flex: none; }

/* La .id-bar vieja queda vacía y oculta desde el JS; esto es cinturón y
   tirantes por si algún camino la volviera a llenar. */
#ses-idbar:empty { display: none; }

@media (max-width: 900px) {
  .pac-ctx { position: static; padding: 11px 13px; }
  .pac-ctx__sello { margin-left: 0; }
  .pac-ctx__pie .btn { width: 100%; }
}

/* ============================================================
   18) TRANSCRIPCIÓN BAJO EL VIDEO — #trx-box (20-jul-2026)
   Reusa la carcasa .pc del "próximo control" (que ya vivía acá), así los
   dos desplegables de la columna del video se ven como hermanos.
   ============================================================ */

/* Chip de estado en el título plegado. Sin esto, con el bloque cerrado no
   habría forma de saber si se está grabando. */
.trx-estado {
  margin-left: auto;
  font-size: .72rem; font-weight: 700;
  padding: 2px 10px; border-radius: 999px;
  background: var(--bg); color: var(--tinta-3);
  border: 1px solid var(--linea);
}
.trx-estado--rec {
  background: #fdecef; color: #8c1233; border-color: transparent;
}
/* Punto rojo delante de "grabando": el estado se reconoce sin leer. */
.trx-estado--rec::before {
  content: ""; display: inline-block; vertical-align: middle;
  width: 6px; height: 6px; border-radius: 50%; background: #be123c;
  margin-right: 6px;
}
.trx-estado--ia {
  background: var(--violeta-claro); color: var(--violeta); border-color: transparent;
}
/* El summary de .pc es flex? No se asume: se fuerza para que el margin-left:auto
   del chip empuje de verdad. */
#trx-box > summary { display: flex; align-items: center; gap: 8px; }

/* La transcripción crece sin fin mientras hablan. Acotada y con scroll propio
   para que NO empuje el layout de la columna del video (regla de cero scroll
   en la sala: lo que crece, crece dentro de su caja). */
#trx-box .transcripcion {
  max-height: 210px;
  overflow-y: auto;
}
#trx-box .ia-box { padding: 0; background: transparent; border: 0; }

@media (max-width: 900px) {
  #trx-box .transcripcion { max-height: 160px; }
}

/* ============================================================
   19) FICHA AGRUPADA POR DESTINO — .fc-grupos (20-jul-2026)
   Los 7 campos de los documentos pasaron de una lista única a tres
   desplegables según QUIÉN recibe cada uno. Hereda .fc-tramite (estilos
   ya existentes); acá solo va lo propio de la agrupación.
   ============================================================ */
.fc-grupos { display: flex; flex-direction: column; gap: 10px; }

/* Cada grupo como tarjeta con identidad propia, para que se lean como tres
   cosas distintas y no como un acordeón partido en tres. */
.fc-g { border: 1px solid var(--linea); border-radius: var(--r-md, 12px); overflow: hidden; }
.fc-g > summary { padding: 10px 13px; background: var(--bg); }
.fc-g[open] > summary { border-bottom: 1px solid var(--linea); }
.fc-g .fc-tramite-cuerpo { padding: 13px; }

/* El grupo interno se distingue: lo que NO sale de la consulta. */
.fc-g--int > summary { background: var(--bg-2, var(--bg)); }
.fc-g--int .fc-tramite-tit { color: var(--tinta-2); }

/* Las etiquetas de campo ya no cargan su destino entre paréntesis (lo dice el
   grupo), así que pueden respirar y verse como rótulo, no como pregunta. */
.fc-g .ri-item h5 { margin-bottom: 5px; }
.fc-g .ri-item + .ri-item { margin-top: 11px; }

/* ============================================================
   20) RECETA Y ÓRDENES — DOS PASOS POR DESTINO (20-jul-2026, tanda 6)
   Antes eran cuatro botones en una fila (.receta-acc, estilos.css:576) con verbos
   casi idénticos y tres destinos distintos. Acá se les da la forma de dos pasos
   numerados: crear (queda acá) y enviar (recién ahí sale por correo).
   ADITIVO: no se toca .receta-acc ni ninguna regla de estilos.css (canario).
   ============================================================ */
.rx-pasos { display: flex; flex-direction: column; gap: 12px; margin-top: 20px; }
.rx-paso {
  border: 1px solid var(--linea);
  border-radius: var(--r-md, 12px);
  padding: 13px;
  background: var(--bg);
}
.rx-paso__tit {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--violeta); margin: 0 0 4px;
}
/* El número es el que hace legible el orden de un vistazo: primero se crea, después
   se envía. Es la corrección que pidió Mauricio ("emitir no significa que se envían"). */
.rx-paso__n {
  flex: 0 0 auto;
  width: 20px; height: 20px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--violeta); color: #fff;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0;
}
.rx-paso__ay { font-size: 0.84rem; color: var(--tinta-2); margin: 0 0 10px; line-height: 1.5; }
.rx-paso__acc { display: flex; gap: 10px; flex-wrap: wrap; }
.rx-paso__acc .btn { flex: 1 1 auto; min-width: 200px; }

/* Chips de "ya creado": sobreviven al mensaje de la línea de estado y son la señal
   visible de que la rehidratación (tanda 6.5) encontró documentos tras un F5. */
.rx-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }
.rx-chips:empty { display: none; }
.rx-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 999px;
  background: rgba(12, 107, 88, 0.10); color: #0c6b58;
  border: 1px solid rgba(12, 107, 88, 0.22);
  font-size: 0.78rem; font-weight: 600;
}

/* Tercer destino, deliberadamente APARTE de los dos pasos: pedirle a la paciente que
   SUBA exámenes previos no emite ni envía documentos. Compartía el ícono de frasco
   con "Emitir orden de exámenes" y por eso se confundían. */
.rx-otra { margin-top: 14px; padding-top: 13px; border-top: 1px dashed var(--linea); }
.rx-otra__ay { font-size: 0.8rem; color: var(--tinta-2); margin: 7px 0 0; line-height: 1.5; }

/* Modal de la ficha: la pregunta "ya existe la receta RX-0012, ¿qué necesitas?"
   (tanda 6.4). Nace [hidden]; la muestra mfPintarEstadoDocs() solo si hay documentos. */
.mf-docs-aviso {
  font-size: 0.85rem; color: var(--tinta); margin: 14px 0 0;
  padding: 9px 11px; border-radius: var(--r-sm, 8px);
  background: var(--bg-2, var(--bg)); border: 1px solid var(--linea);
}

@media (max-width: 760px) {
  .rx-paso__acc .btn { min-width: 100%; }
}

/* ============================================================
   21) TEXTAREAS QUE CRECEN — .cd-ta-grow (20-jul-2026, tanda 7)
   La altura la maneja cdTaAjustar() en medico.js (inline style), NO esta hoja: acá
   solo va el piso, para que el campo no se vea diminuto en el primer pintado ni
   durante el instante previo a la primera medición.
   🔴 El TOPE (~14rem) vive en CD_TA_MAX_PX en medico.js y es innegociable: el panel
   de la sala en llamada mide 74vh (estilos.css:1122-1134) y sin tope una nota larga
   empuja el botón de firmar fuera de la pantalla. El video NO cambia de tamaño.
   ============================================================ */
.cd-ta-grow { min-height: 4.6rem; transition: height 0.08s linear; }
@media (prefers-reduced-motion: reduce) {
  .cd-ta-grow { transition: none; }
}

/* ============================================================
   22) MODAL DE FICHA AGRUPADO — .mf-grupos (20-jul-2026, tanda 1)
   El modal de la agenda pintaba sus 10 campos en fila, sin un solo `if`. Ahora
   reutiliza .fc-grupos/.fc-g de la sala (sección 19); acá va SOLO lo que cambia
   porque el modal usa .campo (label+textarea) donde la sala usa .ri-item (h5).
   ADITIVO: no se toca ninguna regla de la sección 19 ni de historia.css.
   ============================================================ */

/* .campo trae margin-bottom:16px de estilos.css:298. Dentro del cuerpo de un grupo
   el último sobra: dejaba un colchón muerto antes del borde de la tarjeta. */
.mf-grupos .fc-tramite-cuerpo .campo:last-child { margin-bottom: 0; }

/* El aviso de la nota clínica queda pegado a su label dentro del grupo. */
.mf-grupos .fc-nota-aviso { margin-top: 0; }

/* 🔴 "Acuerdos con la paciente" va FUERA de todo desplegable, a la vista.
   Se le da carcasa de tarjeta —igual que los grupos— para que se lea como una
   sección deliberada y no como un campo que quedó suelto entre dos acordeones.
   Borde izquierdo marcado: es el único campo que recoge lo conversado y que la IA
   nunca escribe; si no se nota, no se llena. */
.mf-suelto {
  border: 1px solid var(--linea);
  border-left: 3px solid var(--violeta);
  border-radius: var(--r-md, 12px);
  padding: 13px;
  background: var(--bg);
}
.mf-suelto .campo { margin-bottom: 8px; }
.mf-nota-suelta { margin: 0; }

/* ============================================================
   23) PRÓXIMO CONTROL EN LA PESTAÑA RECETA — .pc-seccion (20-jul-2026, tanda 2)
   #pc-box + #pc-chip se mudaron desde la columna del video al final de la pestaña
   "Receta y órdenes". Acá solo el encabezado que los presenta: las reglas .pc /
   .pc-resumen / .pc-cuerpo de historia.css NO se tocan (son selectores de clase
   sueltos, sin dependencia del contenedor, por eso la mudanza no las afecta).
   El techo de .pc-cuerpo (max-height:320px) sigue siendo suyo y se respeta.
   ============================================================ */
.pc-seccion {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--linea);
}
.pc-seccion__tit {
  margin: 0 0 4px;
  font-size: 0.95rem;
  font-weight: 800;
  color: var(--tinta, #222);
}
.pc-seccion__sub {
  margin: 0 0 10px;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--tinta-2, #555);
}

/* ============================================================
   24) DOCUMENTOS DEL PACIENTE — listado inline (20-jul-2026, tanda 5)
   Reemplaza las "pestañas" de botones del visor por un listado de filas con estado
   (NUEVO / Abierto / Sin abrir). Mismo marcado en el modal de la agenda y en el
   listado inline de la sala: una sola apariencia que mantener.
   Alturas en vh acotadas: dentro de .sesion-panel (74vh, estilos.css:1123) lo que
   crece tiene que crecer DENTRO de su caja, no empujar el layout ni el video.
   ============================================================ */
.ex-lista { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }

.ex-fila {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 9px 11px;
  border: 1px solid var(--linea);
  border-radius: var(--r-md, 12px);
  background: var(--bg);
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: border-color 0.12s ease, background 0.12s ease;
}
.ex-fila:hover { border-color: var(--lavanda, #b9a7e8); background: #fff; }
.ex-fila:focus-visible { outline: 2px solid var(--violeta); outline-offset: 2px; }
.ex-fila.is-on { border-color: var(--violeta); background: #fff; }

/* Llegó DURANTE la consulta: es la señal que pidió Mauricio para poder distinguirlo
   de lo que la paciente había subido días antes. */
.ex-fila.es-nuevo { border-color: #e8b4ad; background: #fff7f6; }

.ex-fila__ic { flex: 0 0 auto; display: inline-flex; color: var(--violeta); }
.ex-fila__txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

/* min-width:0 arriba + estos dos: el nombre largo se recorta en vez de empujar las
   pastillas fuera de la fila. (No se usa inline-flex acá: no recorta.) */
.ex-fila__nom {
  font-weight: 700;
  font-size: 0.88rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ex-fila__meta { font-size: 0.75rem; color: var(--tinta-3, #888); }
.ex-fila__pills { flex: 0 0 auto; display: flex; gap: 5px; align-items: center; }

.ex-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.2px;
  white-space: nowrap;
}
.ex-pill--nuevo    { background: #c0392b; color: #fff; }
.ex-pill--visto    { background: #e6f7ee; color: #0c6b58; }
.ex-pill--sinabrir { background: #f0ecf7; color: #6b5c8a; }

.ex-visor-caja {
  border: 1px solid #ece7f5;
  border-radius: 10px;
  background: #faf7ff;
  overflow: hidden;
}
.ex-visor { display: block; width: 100%; height: 46vh; min-height: 300px; border: 0; }

/* 🔴 Estado inicial: el visor arranca VACÍO. No es cosmético — abrir un documento
   solo golpea api/adjuntos.php?action=ver, que escribe cd_log('adjunto_ver'), que es
   justo el registro del que sale el "Abierto / Sin abrir" de arriba. Auto-abrir
   fabricaría la evidencia que después se muestra como hecho. */
.ex-visor-vacio {
  margin: 0;
  padding: 34px 16px;
  text-align: center;
  font-size: 0.86rem;
  color: var(--tinta-3, #888);
}
.ex-acciones { margin-top: 10px; }

@media (max-width: 900px) {
  .ex-visor { height: 40vh; min-height: 240px; }
}

/* ============================================================
   ARREGLO 3 — EL DÍA DISPONIBLE SE RECONOCE (20-jul-2026)
   ------------------------------------------------------------
   ADITIVO y CSS-ONLY. Anclado a #agenda-dias (calendario de la PACIENTE).
   🔴 NO toca #agenda-medico: esa vista queda exactamente como está.
   Va al FINAL del archivo a propósito: comparte especificidad con el bloque
   del reskin (#agenda-dias .ag-dia--libre, más arriba en este mismo archivo)
   y necesita ganarle por ORDEN DE FUENTE. Si se mueve más arriba, no aplica.

   El problema medido NO era el tamaño: era que el día reservable dependía de
   UNA sola señal débil — un punto de 5px con 2.74:1 de contraste, bajo el
   mínimo de 3. Ahora son CUATRO señales simultáneas (fondo, borde, color del
   número y grosor), así que el día se reconoce de un vistazo y también sin
   distinguir bien los colores.
   Medido en navegador: número violeta sobre lila 5.11:1 · borde sobre la
   página 5.58:1 (antes 2.74:1).
   ============================================================ */
#agenda-dias .ag-dia--libre{
  background:var(--violeta-claro);
  border:1.5px solid var(--violeta);
  color:var(--violeta);
  font-weight:750;
}
#agenda-dias .ag-dia--libre .ag-dia-n{color:var(--violeta);font-weight:750}
/* El punto deja de ser la única señal, pero se conserva y sube de contraste. */
#agenda-dias .ag-dia--libre::after{background:var(--violeta)}
/* Hover: se replica la especificidad de estilos.css (:hover:not(.ag-dia--off))
   para ganarle por orden de fuente, igual que hace el bloque del reskin. */
#agenda-dias .ag-dia--libre:hover:not(.ag-dia--off){
  background:var(--violeta-claro);border-color:var(--lavanda);
}
/* Seleccionado: DESPUÉS de --libre para conservar el gradiente del reskin. */
#agenda-dias .ag-dia--sel,
#agenda-dias .ag-dia--sel.ag-dia--libre{
  background:var(--grad-primario);border-color:transparent;color:#fff;
}
#agenda-dias .ag-dia--sel .ag-dia-n{color:#fff}
#agenda-dias .ag-dia--sel.ag-dia--libre::after{background:#fff}

/* --- La leyenda deja de mentir ---------------------------------------------
   La leyenda de la paciente (agenda-cal.js, misma función para ambos roles)
   decía "busca el verde" y en pantalla no había ningún verde: el reskin
   reescribió las celdas pero la leyenda seguía con los colores de
   estilos.css (#0b7266 verde / #c0392b rojo), que ya no existen en el
   calendario. Ahora cada muestra ES la misma casilla en chico.
   🔴 Sin número adentro (decisión de Mauricio: parecía una fecha).
   --------------------------------------------------------------------------- */
#agenda-dias .ag-lg--libre{
  background:var(--violeta-claro);
  border:2px solid var(--violeta);
}
/* "Sin horas" y "No atiende" comparten aspecto porque las CELDAS también lo
   comparten en este diseño (ambas: fondo --bg, sin borde, opacity .4).
   La muestra es fiel a lo que se ve. Ver nota en la entrega. */
#agenda-dias .ag-lg--lleno,
#agenda-dias .ag-lg--vacio{
  background:var(--bg);border:1px solid var(--linea);opacity:.55;
}

/* --- Altura táctil de la celda en teléfono ---------------------------------
   El reskin puso aspect-ratio:1 con min-height:0, que anula el min-height:52px
   de estilos.css:983. Con 7 columnas en 360px la celda quedaba en 36.9px
   medidos — bajo el mínimo táctil de 44. Se suelta la proporción y se fija el
   piso; el ancho lo sigue dando la grilla.
   --------------------------------------------------------------------------- */
@media (max-width:560px){
  #agenda-dias .ag-dia{aspect-ratio:auto;min-height:44px}
}

/* ============================================================
   25) CERTIFICADO MÉDICO — redactor con vista previa (23-jul-2026)
   ADITIVO. No toca estilos.css (canario). Reusa .campo/.btn/.rx-chip/.rx-paso__ay/
   .sello/.cd-ta-grow. La vista previa vive en un <iframe srcdoc> con el CSS REAL
   del PDF (viene dentro del HTML del builder), aislado del portal.
   🔴 Sin franja "es-alto"/escalado: la advertencia es UNA sola línea fija
   (decisión de Mauricio, 23-jul). Sin inputs Desde/Hasta: ninguna plantilla los usa.
   ============================================================ */
.cert-cab { margin-bottom: 12px; }
.cert-cab__volver { display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 0 4px; background: none; border: 0; cursor: pointer;
  color: var(--violeta); font-weight: 700; font-size: 0.86rem; }
.cert-cab__volver svg { width: 15px; height: 15px; }
.cert-cab h3 { display: flex; align-items: center; gap: 9px; font-size: 1.1rem; margin: 4px 0 2px; }
.cert-cab h3 svg { width: 20px; height: 20px; color: var(--violeta); }
.cert-para { font-size: 0.85rem; color: var(--tinta-2); margin: 0; }

/* Advertencia legal: UNA línea, naranja de la marca de DOCUMENTOS (#FF9300), fija,
   arriba, antes del selector. No colapsable. El texto lo fija Carolina (§1.b). */
.cert-legal { display: flex; gap: 9px; align-items: center; margin: 12px 0 16px;
  border: 1px solid #f0d9b0; border-left: 4px solid #FF9300; background: #fffdf8;
  border-radius: var(--r-sm, 12px); padding: 11px 13px;
  font-size: 0.86rem; line-height: 1.5; color: #5a4a2f; }
.cert-legal svg { flex: 0 0 auto; width: 18px; height: 18px; color: #b46a00; }

.cert-cols { display: block; }
.cert--ancho .cert-cols { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,460px);
  gap: 22px; align-items: start; }
.cert--ancho .cert-vista { position: sticky; top: 12px; }

.cert-tpl-grid { display: grid; gap: 8px; }
.cert--ancho .cert-tpl-grid { grid-template-columns: 1fr 1fr; }
.cert-tpl { position: relative; display: block; min-height: 44px; padding: 11px 13px; cursor: pointer;
  border: 2px solid var(--linea); border-radius: 14px; background: #fff; }
.cert-tpl input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.cert-tpl__n { display: block; font-weight: 700; font-size: 0.9rem; color: var(--tinta); }
.cert-tpl__d { display: block; font-size: 0.8rem; color: var(--tinta-2); margin-top: 2px; line-height: 1.45; }
.cert-tpl.es-on { border-color: var(--violeta); background: var(--violeta-claro); }
.cert-tpl:focus-within { outline: 3px solid var(--lavanda); outline-offset: 2px; }

.cert-cuenta { display: block; text-align: right; font-size: 0.75rem; color: var(--tinta-3); margin-top: 4px; }
.cert-cuenta.es-tope { color: #c0392b; font-weight: 700; }

/* Casillas de plantilla (tratamiento a petición / hechos de la ficha). */
.cert-casilla { display: flex; gap: 9px; align-items: flex-start; margin: 4px 0 12px;
  font-size: 0.85rem; color: var(--tinta-2); line-height: 1.45; cursor: pointer; }
.cert-casilla input { margin-top: 3px; flex: 0 0 auto; width: 17px; height: 17px; }
/* 🔴 23-jul-2026 — SIN ESTA LÍNEA EL ATRIBUTO hidden NO SIRVE ACÁ. `display:flex` es
   una declaración de AUTOR y le gana a `[hidden]{display:none}`, que la trae el
   navegador (origen user-agent). medico.js oculta estas casillas con `.hidden = true`
   según la plantilla elegida; sin esta regla se veían SIEMPRE, y la de "indicación
   consta" se veía con el rótulo VACÍO porque su texto lo escribe el servidor solo
   cuando de verdad se pide. Es el bug de la "casilla sin texto" que reportó Mauricio.
   Mismo patrón ya usado en .hv-evento[hidden] (historia.css) y .ia-aviso[hidden]
   (estilos.css). */
.cert-casilla[hidden] { display: none; }

.cert-visor__cab { display: flex; align-items: baseline; gap: 10px; margin: 18px 0 7px; }
.cert--ancho .cert-visor__cab { margin-top: 0; }
.cert-visor__cab h4 { margin: 0; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--violeta); }
.cert-estado { margin-left: auto; font-size: 0.75rem; color: var(--tinta-3); }
.cert-estado.es-trabajando { color: var(--lavanda); }
.cert-estado.es-ok { color: var(--menta); }
/* Caja PROPIA (no reuso de .ex-visor-caja): mismos valores, dominios distintos. Si
   mañana cambia el visor de exámenes, el certificado no se entera. */
.cert-visor-caja { border: 1px solid #ece7f5; border-radius: 10px; background: #faf7ff; overflow: hidden; }
.cert-hoja { display: block; width: 100%; height: 44vh; min-height: 280px; border: 0; background: #fff; }
.cert--ancho .cert-hoja { height: 62vh; }
.cert-visor-vacio { padding: 22px 16px; text-align: center; font-size: 0.85rem;
  color: var(--tinta-2); line-height: 1.55; }
.cert-vista__ay { font-size: 0.78rem; color: var(--tinta-3); margin: 7px 0 0; }

.cert-aviso { border-radius: var(--r-sm, 12px); padding: 11px 13px; margin: 0 0 12px;
  font-size: 0.86rem; line-height: 1.5; }
.cert-aviso.es-info  { background: var(--violeta-claro); color: var(--tinta);  border: 1px solid #ddd4ff; }
.cert-aviso.es-ojo   { background: #fbf0da;              color: #5a4a2f;       border: 1px solid #e8d2a0; }
.cert-aviso.es-error { background: #fdf3f2;              color: #8a2318;       border: 1.5px solid #c0392b; }
.cert-aviso .btn { margin-top: 9px; }

.cert-acc { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
.cert-acc .btn { flex: 1 1 auto; min-width: 190px; }

.cert-emitido { text-align: center; padding: 26px 16px; }
.cert-emitido__folio { font-family: ui-monospace, "DejaVu Sans Mono", monospace;
  font-size: 1.5rem; font-weight: 800; color: var(--tinta); margin: 10px 0 2px; }
.cert-emitido__ay { font-size: 0.86rem; color: var(--tinta-2); margin: 0 0 18px; }

.cert-hist { margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--linea); }
.cert-hist summary { display: flex; align-items: center; min-height: 44px; cursor: pointer;
  font-size: 0.84rem; font-weight: 700; color: var(--violeta); }
.cert-hist__l { margin: 4px 0 0; padding-left: 18px; font-size: 0.83rem; color: var(--tinta-2); }

/* Botón "Emitir certificado" dentro de la hoja de vida (ubicación b). */
.hv-acciones { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 14px; }
.hv-acciones .btn { min-height: 44px; }

@media (max-width: 760px) {
  /* 🔴 EL COLAPSO DE LA GRILLA FALTABA. .cert--ancho (entrada por hoja de vida) fija
     dos columnas minmax(0,1fr) + minmax(0,460px): bajo ~500px la columna fija se come
     todo el ancho y la del formulario queda en 0px MEDIDOS (390px: .cert-form = 0),
     con la vista previa montada encima. En la sala no se ve porque ahí .cert-cols ya
     es block. Se colapsa a una sola columna y se suelta el sticky: pegado, el visor
     tapaba el formulario al desplazarse en pantalla angosta. */
  .cert--ancho .cert-cols { display: block; }
  .cert--ancho .cert-vista { position: static; }
  .cert-acc .btn { min-width: 100%; }
  .cert-hoja { height: 40vh; min-height: 240px; }
  .cert--ancho .cert-hoja { height: 40vh; }
}
/* Chips de plantilla: a dos columnas bajo 560px el nombre + la descripción quedan en
   una columna de ~170px. Una sola columna mantiene el objetivo táctil y el texto. */
@media (max-width: 560px) {
  .cert--ancho .cert-tpl-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .cert-visor-caja *, .cert-estado { animation: none !important; transition: none !important; }
}

/* ============================================================
   26) NOTIFICACIÓN GES — formulario de constancia art. 24, Ley 19.966 (24-jul-2026)
   ADITIVO, al final del archivo. No toca estilos.css (canario) ni el bloque 25
   del certificado: mismos valores visuales, clases PROPIAS. Si mañana cambia el
   redactor de certificados, la notificación GES no se entera (y al revés).
   La vista previa vive en un <iframe srcdoc> con el CSS REAL del PDF —viene
   dentro del HTML que dibuja cd_ges_html()—, aislado del portal.
   ============================================================ */

/* 🔴 ESTA REGLA NO ES COSMÉTICA: SIN ELLA `hidden` NO SIRVE ACÁ.
   `[hidden]{display:none}` la trae el navegador (origen user-agent) y CUALQUIER
   declaración `display` de AUTOR le gana. Es el bug exacto que vivió Mauricio con
   la casilla del certificado: medico.js la ocultaba con `.hidden = true` y se veía
   igual, además con el rótulo vacío. Acá el módulo oculta cuatro cosas por atributo
   —el bloque oncológico, el bloque no oncológico, los campos del representante y el
   aviso de etapa—, así que se cierra por regla, de una vez y para todo el
   subárbol: cualquier nodo futuro con `hidden` dentro del formulario queda cubierto
   sin que nadie tenga que acordarse. Mismo patrón que .cert-casilla[hidden],
   .hv-evento[hidden] (historia.css) y .ia-aviso[hidden] (estilos.css). */
#ges-redactor [hidden] { display: none !important; }
.ges-casilla[hidden], .ges-bloque[hidden], .ges-aviso[hidden] { display: none !important; }

.ges-cab { margin-bottom: 12px; }
.ges-cab__volver { display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 0 4px; background: none; border: 0; cursor: pointer;
  color: var(--violeta); font-weight: 700; font-size: 0.86rem; }
.ges-cab__volver svg { width: 15px; height: 15px; }
.ges-cab h3 { display: flex; align-items: center; gap: 9px; font-size: 1.1rem; margin: 4px 0 2px; }
.ges-cab h3 svg { width: 20px; height: 20px; color: var(--violeta); }
.ges-para { font-size: 0.85rem; color: var(--tinta-2); margin: 0; }
.ges-ay { font-size: 0.78rem; color: var(--tinta-3); margin: 5px 0 0; line-height: 1.5; }
.ges-sub { margin: 22px 0 8px; font-size: 0.78rem; text-transform: uppercase;
  letter-spacing: 0.5px; color: var(--violeta); }

/* Encuadre legal: qué ES y qué NO ES este documento. Una línea, fija, arriba.
   Naranja de la marca de DOCUMENTOS (#FF9300), igual que .cert-legal. */
.ges-legal { display: flex; gap: 9px; align-items: center; margin: 12px 0 16px;
  border: 1px solid #f0d9b0; border-left: 4px solid #FF9300; background: #fffdf8;
  border-radius: var(--r-sm, 12px); padding: 11px 13px;
  font-size: 0.86rem; line-height: 1.5; color: #5a4a2f; }
.ges-legal svg { flex: 0 0 auto; width: 18px; height: 18px; color: #b46a00; }

.ges-cols { display: block; }
/* 🔴 620px, no 460 (24-jul v2, orden de Mauricio: "la vista previa más grande").
   El formulario ya no necesita dos columnas de chips —el problema GES es texto
   libre— y con el acordeón solo hay UNA etapa abierta a la vez, así que la
   columna izquierda pide menos ancho del que pedía. El precio es que la pantalla
   mínima para dos columnas sube: por eso el colapso se adelanta a 1020px. */
.ges--ancho .ges-cols { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,620px);
  gap: 22px; align-items: start; }
.ges--ancho .ges-vista { position: sticky; top: 12px; }

/* Consulta a la que queda enlazada la constancia. */
.ges-cita { display: flex; align-items: center; gap: 8px; margin: 0 0 12px;
  border: 1px solid var(--linea); border-radius: var(--r-sm, 12px); padding: 9px 12px;
  background: #fff; font-size: 0.84rem; color: var(--tinta-2); }
.ges-cita svg { flex: 0 0 auto; width: 15px; height: 15px; color: var(--violeta); }

/* 🔴 FECHA Y HORA DESTACADA (requisito explícito de Mauricio: inicia los plazos
   GES). NO es un input y no puede serlo: la pone el servidor en hora de Chile al
   emitir. El recuadro amarillo es el MISMO tratamiento que lleva en el PDF, para
   que la médica reconozca en el formulario lo que va a ver impreso. */
.ges-fh { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  border: 2px solid #e0b500; background: #fff6d8; border-radius: var(--r-sm, 12px);
  padding: 10px 13px; margin: 0 0 4px; }
.ges-fh__lbl { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.5px;
  font-weight: 700; color: #6b5300; }
.ges-fh__val { font-weight: 800; font-size: 1.02rem; color: #3d2f00; margin-left: auto; }

/* 🔴 PROBLEMA GES EN TEXTO LIBRE (24-jul v2). Dos casillas espejo del formulario
   MINSAL de papel: general y oncológica. La exclusión la hace el módulo
   deshabilitando la otra mientras una tiene texto; acá solo se le da al estado
   `disabled` una apariencia que se entienda —apagado, no roto— porque un input
   deshabilitado sin señal visual parece un bug del sistema. El candado de verdad
   sigue siendo el 422 del servidor (problema_en_ambas_casillas). */
.ges-prob input:disabled { background: #f4f2f8; color: var(--tinta-3); cursor: not-allowed; }
.ges-prob input:disabled::placeholder { color: #b9b3c7; }

/* Chips de problema GES de la versión 1 (lista guiada).
   🔴 NO SE BORRAN aunque el módulo nuevo ya no los pinte: `medico.html` carga
   `medico.js` SIN cache-busting, así que hay navegadores que van a seguir
   dibujando la grilla de tarjetas días después del deploy (es el mismo motivo por
   el que el backend conserva el shim de `problema_id`). Sin estas reglas, esas
   médicas verían radios crudos sobre un formulario legal. Se retiran cuando se
   retire el shim, como decisión y no como olvido. */
.ges-tpl-grid { display: grid; gap: 8px; }
.ges--ancho .ges-tpl-grid { grid-template-columns: 1fr 1fr; }
.ges-tpl { position: relative; display: block; min-height: 44px; padding: 11px 13px; cursor: pointer;
  border: 2px solid var(--linea); border-radius: 14px; background: #fff; }
.ges-tpl input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.ges-tpl__n { display: block; font-weight: 700; font-size: 0.9rem; color: var(--tinta); }
.ges-tpl__d { display: block; font-size: 0.8rem; color: var(--tinta-2); margin-top: 2px; line-height: 1.45; }
.ges-tpl.es-on { border-color: var(--violeta); background: var(--violeta-claro); }
.ges-tpl:focus-within { outline: 3px solid var(--lavanda); outline-offset: 2px; }

/* Bloques excluyentes: oncológico (6 etapas) / no oncológico (texto fijo). */
.ges-bloque { margin: 14px 0 4px; padding: 13px; border: 1px solid var(--linea);
  border-radius: var(--r-sm, 12px); background: #fbfaff; }
.ges-bloque > label { display: block; font-weight: 700; font-size: 0.84rem;
  color: var(--tinta); margin-bottom: 8px; }
.ges-etapas, .ges-prev { display: flex; flex-wrap: wrap; gap: 8px; }
.ges-etapa { display: inline-flex; align-items: center; gap: 7px; min-height: 44px;
  padding: 0 12px; border: 2px solid var(--linea); border-radius: 12px; background: #fff;
  cursor: pointer; font-size: 0.85rem; color: var(--tinta); }
.ges-etapa input { width: 17px; height: 17px; flex: 0 0 auto; }
.ges-etapa:focus-within { outline: 3px solid var(--lavanda); outline-offset: 2px; }
.ges-etapa:has(input:checked) { border-color: var(--violeta); background: var(--violeta-claro); }

/* Texto FIJO del bloque no oncológico: dice lo que hará el servidor. NO es un
   control marcable, y por eso el doble marcaje no es advertido sino imposible. */
.ges-fijo { display: flex; gap: 9px; align-items: flex-start; margin: 0;
  font-size: 0.85rem; line-height: 1.5; color: var(--tinta-2); }
.ges-fijo svg { flex: 0 0 auto; width: 15px; height: 15px; margin-top: 3px; color: var(--menta); }

/* Sellos "precargado" / "completa": de un vistazo, qué trae el sistema y qué falta.
   Los tres campos con "completa" (dirección de calle, región, nombre social) NO
   existen en cd_pacientes y la región NO es derivable de la comuna. */
.ges-campo label { display: flex; align-items: center; gap: 8px; }
.ges-sello { font-size: 0.68rem; font-weight: 700; border-radius: 4px; padding: 1px 6px;
  text-transform: lowercase; letter-spacing: 0.2px; }
.ges-sello.es-precargado { color: #0f6b4a; background: #e6f6ef; }
.ges-sello.es-completa   { color: #8a5300; background: #fff3df; }

/* ------------------------------------------------------------
   ACORDEÓN DE ETAPAS (24-jul v2, orden de Mauricio: "que se abra la sección 1 y
   después pasemos a la 2"). Cuatro etapas: problema · antecedentes · previsión ·
   revisar y emitir.
   🔴 EL CUERPO SE OCULTA CON `hidden`, NO CON DISPLAY PROPIO: los campos de las
   etapas cerradas SIGUEN EN EL DOM, que es lo que mantiene vivo el cuerpo del POST
   (gesCuerpo lee del DOM) y el listener delegado del veredicto (D2). Si el
   acordeón desmontara los campos, el formulario emitiría la mitad de los datos.
   La regla `#ges-redactor [hidden]{display:none!important}` de arriba ya cubre
   este nodo; se repite acá por el mismo motivo que .ges-bloque[hidden]: si mañana
   alguien mueve el acordeón fuera de #ges-redactor, no se destapa solo.
   ------------------------------------------------------------ */
.ges-etp { border: 1px solid var(--linea); border-radius: var(--r-sm, 12px);
  background: #fff; margin: 0 0 10px; overflow: hidden; }
.ges-etp__cuerpo[hidden] { display: none !important; }
.ges-etp.es-abierta { border-color: var(--violeta); }
.ges-etp__cab { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 52px;
  padding: 10px 13px; background: none; border: 0; cursor: pointer; text-align: left;
  font: inherit; color: var(--tinta); }
.ges-etp__cab:focus-visible { outline: 3px solid var(--lavanda); outline-offset: -3px; }
.ges-etp__cab[disabled] { cursor: default; opacity: 0.65; }
.ges-etp__num { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; background: var(--violeta-claro);
  color: var(--violeta); font-size: 0.82rem; font-weight: 800; }
.ges-etp__tit { font-weight: 700; font-size: 0.9rem; }
.ges-etp__ck { margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.75rem; color: var(--tinta-3); }
.ges-etp__ck svg { width: 16px; height: 16px; }
.ges-etp.es-ok .ges-etp__num { background: var(--menta, #1f9d78); color: #fff; }
.ges-etp.es-ok .ges-etp__ck { color: var(--menta, #1f9d78); }
.ges-etp__cuerpo { padding: 2px 13px 14px; border-top: 1px solid var(--linea); }
.ges-etp__pie { margin-top: 14px; }
.ges-etp__pie .btn { min-width: 190px; }
/* Error local de la etapa. 🔴 Es SOLO UX (adelanta lo que igual diría el 422):
   se escribe siempre, con texto o vacío, para no repetir el bug del rótulo que
   nacía vacío y se quedaba vacío. */
.ges-etp__err { margin: 10px 0 0; font-size: 0.82rem; line-height: 1.45; color: #8a2318; }
.ges-etp__err[hidden] { display: none !important; }

.ges-casilla { display: flex; gap: 9px; align-items: flex-start; margin: 16px 0 4px;
  font-size: 0.85rem; color: var(--tinta-2); line-height: 1.45; cursor: pointer; }
.ges-casilla input { margin-top: 3px; flex: 0 0 auto; width: 17px; height: 17px; }

.ges-visor__cab { display: flex; align-items: baseline; gap: 10px; margin: 18px 0 7px; }
.ges--ancho .ges-visor__cab { margin-top: 0; }
.ges-visor__cab h4 { margin: 0; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--violeta); }
.ges-estado { margin-left: auto; font-size: 0.75rem; color: var(--tinta-3); }
.ges-estado.es-trabajando { color: var(--lavanda); }
.ges-estado.es-ok { color: var(--menta); }
.ges-visor-caja { border: 1px solid #ece7f5; border-radius: 10px; background: #faf7ff; overflow: hidden; }
.ges-hoja { display: block; width: 100%; height: 44vh; min-height: 280px; border: 0; background: #fff; }
/* 🔴 72vh / mínimo 520px (24-jul v2): la hoja del PDF es carta vertical, así que
   lo que se gana leyendo es ALTO, no ancho. El mínimo en px es el que salva a los
   notebooks de 768px de alto, donde 72vh son 553px pero 62vh eran 476 y la firma
   quedaba siempre bajo el pliegue. En la SALA no aplica (no lleva .ges--ancho):
   ahí sigue en 44vh para no tapar el video de la paciente. */
.ges--ancho .ges-hoja { height: 72vh; min-height: 520px; }
.ges-visor-vacio { padding: 22px 16px; text-align: center; font-size: 0.85rem;
  color: var(--tinta-2); line-height: 1.55; }
.ges-vista__ay { font-size: 0.78rem; color: var(--tinta-3); margin: 7px 0 0; }

.ges-aviso { border-radius: var(--r-sm, 12px); padding: 11px 13px; margin: 0 0 12px;
  font-size: 0.86rem; line-height: 1.5; }
.ges-aviso--inline { margin: 10px 0 0; }
.ges-aviso.es-info  { background: var(--violeta-claro); color: var(--tinta); border: 1px solid #ddd4ff; }
.ges-aviso.es-ojo   { background: #fbf0da;              color: #5a4a2f;      border: 1px solid #e8d2a0; }
.ges-aviso.es-error { background: #fdf3f2;              color: #8a2318;      border: 1.5px solid #c0392b; }
.ges-aviso .btn { margin-top: 9px; }

.ges-acc { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }
.ges-acc .btn { flex: 1 1 auto; min-width: 190px; }

.ges-emitido { text-align: center; padding: 26px 16px; }
.ges-emitido__folio { font-family: ui-monospace, "DejaVu Sans Mono", monospace;
  font-size: 1.5rem; font-weight: 800; color: var(--tinta); margin: 10px 0 2px; }
.ges-emitido__ay { font-size: 0.86rem; color: var(--tinta-2); margin: 0 0 18px; }

/* 🔴 EL COLAPSO SE ADELANTA A 1020px (24-jul v2) Y SE SEPARA DEL RESTO.
   Antes todo vivía en un solo @media de 760px. Con la preview en 620px, a 900px
   de ventana la columna del formulario quedaría en ~250px: ilegible. Pero mover
   el bloque entero a 1020px habría cambiado TAMBIÉN la sala (botones a 100% y
   hoja a 40vh en cualquier notebook), y la sala no se toca en esta tanda. Por eso
   son dos bloques: acá SOLO lo que depende de las dos columnas (.ges--ancho), y
   más abajo, intacto en 760px, lo que aplica también a la sala. */
@media (max-width: 1020px) {
  .ges--ancho .ges-cols { display: block; }
  .ges--ancho .ges-vista { position: static; }
  /* Una columna: la hoja pasa a ser un bloque más de la página, con la misma
     altura que ya tiene en la sala. El mínimo de 520px se retira a propósito —en
     una ventana angosta obligaría a hacer scroll para llegar a los botones. */
  .ges--ancho .ges-hoja { height: 44vh; min-height: 280px; }
}
@media (max-width: 760px) {
  /* Mismo colapso que el certificado y por el mismo motivo medido: bajo ~500px la
     columna fija se come el ancho y la del formulario queda en 0px. */
  .ges-acc .btn { min-width: 100%; }
  .ges-etp__pie .btn { min-width: 100%; }
  .ges-hoja { height: 40vh; min-height: 240px; }
  .ges--ancho .ges-hoja { height: 40vh; min-height: 240px; }
}
@media (max-width: 560px) {
  .ges--ancho .ges-tpl-grid { grid-template-columns: 1fr; }
  .ges-fh__val { margin-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ges-visor-caja *, .ges-estado { animation: none !important; transition: none !important; }
}
