/* ===========================================================================
   Mioo — sistema visual
   ---------------------------------------------------------------------------
   Implementación del rediseño hecho en Claude Design (proyecto «Mioo — sistema
   de diseño», 31-jul-2026). Minimalista de verdad: jerarquía por tamaño y peso,
   casi sin líneas ni cajas, una sola sombra para lo único que flota.

   La regla que gobierna el color no es estética: la interfaz TIENE que
   distinguir siempre lo que una persona afirmó de lo que la app dedujo, y lo
   vigente de lo retirado. Por eso los cinco estados de un dato son tokens de
   primera clase, y cada uno lleva SIEMPRE su palabra al lado del color.

   Tres temas: claro, oscuro y mioo. Todos los pares texto/fondo dan 4.5:1 o
   más, medido con la fórmula de WCAG y no a ojo.
   =========================================================================== */

/* --- claro (y base de todo) ---------------------------------------------- */
:root {
  color-scheme: light;

  --fondo:        #FFFFFF;
  --superficie:   #F6F6F8;   /* campos, pastillas, filas activas */
  --superficie-2: #ECECF1;
  --tinta:        #17171B;
  --tinta-2:      #52525C;
  --tinta-3:      #6B6B76;   /* mínimo para texto */
  --linea:        #ECECEF;   /* casi no se usa: la barra y poco más */

  --mioo:         #5140D9;
  --sobre-mioo:   #FFFFFF;
  --mioo-suave:   #EFECFC;

  /* Los cinco estados de un dato. Ninguno es decorativo. */
  --verificado:   #0B7A50;   /* canal probado con código, con fecha */
  --inferido:     #8F6400;   /* lo puso el GPS o el reloj, no una persona */
  --pendiente:    #AE4600;   /* propuesto por el contacto, sin revisar */
  --retirado:     #6E6E79;   /* valió y dejó de valer; nunca se borra */
  --sinsync:      #2160C8;   /* guardado en el teléfono, no en el servidor */
  --peligro:      #C22F2F;

  --sombra-tono:  rgba(10, 10, 14, .16);

  /* El rojo de grabar. Vivía suelto como #E5484D en dos reglas.
     No puede ser `--peligro`: peligro cambia con el tema, y la grabadora vive
     siempre sobre la cámara, a oscuras. El mismo rojo en los tres temas es lo
     correcto aquí, igual que el blanco fijo de la caja del QR — por eso se declara
     una vez y NO se redefine en los bloques de tema. */
  --rec: #E5484D;

  /* --- forma: una sola sombra, para lo único que flota ------------------- */
  --r-md: 14px;  --r-lg: 18px;  --r-hoja: 24px;  --r-full: 999px;
  --sombra-flot: 0 12px 40px var(--sombra-tono);

  --esp-1: 4px;  --esp-2: 8px;  --esp-3: 12px;  --esp-4: 16px;
  --esp-5: 24px; --esp-6: 32px; --esp-7: 48px;  --esp-8: 64px;

  --fuente: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* Rápido, con salida suave. Nada debe notarse como «animación».
       --dur-1  responde al dedo (acuse: ¿me has oído?)
       --dur-2  mueve muebles (algo entra, sale o cruza)
       --dur-3  SOLO trayectos de ancho completo
     La tercera no estaba y el cruce entre caras de la hoja usaba 260ms escritos a
     mano en el JavaScript. Son ~390px de viaje, el más largo de la app, y a 180ms
     el ojo no lo sigue igual — pero un número suelto que ninguna otra pieza puede
     heredar es justo lo que un sistema no debe tener. Se declara con el valor que
     ya se aprobó con el dedo, en vez de bajarlo a ciegas para que cuadre. */
  --dur-1: 120ms;  --dur-2: 180ms;  --dur-3: 260ms;
  --curva: cubic-bezier(.2, 0, 0, 1);

  --barra: 56px;
  --barra-total: calc(var(--barra) + env(safe-area-inset-bottom, 0px));
  --ancho: 430px;   /* la app es una columna de teléfono, también en escritorio */
}

/* --- oscuro --------------------------------------------------------------
   Se declara como bloque reutilizable y se aplica por dos vías: automática
   (preferencia del sistema, solo si el usuario no eligió tema) y explícita.

   La ficha original usaba light-dark(). Aquí no, a propósito: en un navegador
   que no lo soporta, `--fondo: light-dark(…)` queda inválido, `var(--fondo)`
   no resuelve y se puede acabar con texto blanco sobre blanco. Este patrón
   funciona en todas partes y además es el que permite un tercer tema. */
@media (prefers-color-scheme: dark) {
  :root:not([data-tema]) {
    color-scheme: dark;
    --fondo:        #0C0C0F;
    --superficie:   #17171C;
    --superficie-2: #23232B;
    --tinta:        #F4F4F6;
    --tinta-2:      #B3B3BD;
    --tinta-3:      #8D8D98;
    --linea:        #24242C;
    --mioo:         #A99EFF;
    --sobre-mioo:   #16123A;
    --mioo-suave:   #201C3A;
    --verificado:   #4ED2A0;
    --inferido:     #E3B053;
    --pendiente:    #F49366;
    --retirado:     #83838E;
    --sinsync:      #6FA8FF;
    --peligro:      #F17E7E;
    --sombra-tono:  rgba(0, 0, 0, .55);
  }
}

:root[data-tema="oscuro"] {
  color-scheme: dark;
  --fondo:        #0C0C0F;
  --superficie:   #17171C;
  --superficie-2: #23232B;
  --tinta:        #F4F4F6;
  --tinta-2:      #B3B3BD;
  --tinta-3:      #8D8D98;
  --linea:        #24242C;
  --mioo:         #A99EFF;
  --sobre-mioo:   #16123A;
  --mioo-suave:   #201C3A;
  --verificado:   #4ED2A0;
  --inferido:     #E3B053;
  --pendiente:    #F49366;
  --retirado:     #83838E;
  --sinsync:      #6FA8FF;
  --peligro:      #F17E7E;
  --sombra-tono:  rgba(0, 0, 0, .55);
}

/* --- estilo mioo ---------------------------------------------------------
   La paleta pastel del operador: #CFF5E3, #F9FFFE, #AEE6CD, #E8F2FF, #3D6D60.
   Se usa tal cual para el fondo, las superficies y el azul hielo.

   Dos ajustes, ambos por contraste medido y no por gusto:
   · la marca es #2F5F51, el verde hondo oscurecido — #3D6D60 daba 4.22:1 sobre
     la menta y no llegaba al mínimo;
   · los cinco estados conservan su familia de tono, porque su semántica no
     depende del tema, retemplados para pasar sobre estos fondos de menta.

   La marca es verde y `verificado` también: son vecinos de tono. Se distinguen
   porque el sello lleva siempre su palabra, que es la regla del sistema. */
:root[data-tema="mioo"] {
  color-scheme: light;
  --fondo:        #F9FFFE;
  --superficie:   #CFF5E3;
  --superficie-2: #AEE6CD;
  --tinta:        #0E1A16;
  --tinta-2:      #3A4B45;
  --tinta-3:      #4E5F5A;
  --linea:        #D6EDE3;
  --mioo:         #2F5F51;
  --sobre-mioo:   #F9FFFE;
  --mioo-suave:   #E8F2FF;
  --verificado:   #0A6E3F;
  --inferido:     #7E5600;
  --pendiente:    #A03D00;
  --retirado:     #586865;
  --sinsync:      #1B54B8;
  --peligro:      #B32626;
  --sombra-tono:  rgba(20, 60, 48, .18);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* === base ================================================================ */

* { box-sizing: border-box; }

html, body {
  margin: 0; background: var(--fondo); color: var(--tinta);
  font-family: var(--fuente); font-size: 16px; line-height: 1.5;
  -webkit-font-smoothing: antialiased; overscroll-behavior-y: none;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, p { margin: 0; }
h1 { font-size: 1.75rem; font-weight: 680; letter-spacing: -.025em; line-height: 1.15; }
a { color: var(--mioo); text-decoration: none; }
a:hover { text-decoration: underline; }
s { color: var(--retirado); text-decoration-thickness: 1px; }
:focus-visible { outline: 2px solid var(--mioo); outline-offset: 2px; border-radius: 6px; }

/* `hidden` tiene que ganar SIEMPRE. La regla del navegador es `[hidden]{display:none}`
   con especificidad de elemento, así que cualquier clase con `display` le gana sin
   querer: así fue como el aviso de «sin conexión» se quedó visible con wifi, porque
   .sin-red es inline-flex. */
[hidden] { display: none !important; }

/* Solo para lectores de pantalla: los estados nunca dependen del color. */
.sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* === estructura ==========================================================
   svh, nunca dvh: la barra de Safari aparece y desaparece al hacer scroll y
   dvh salta con ella. La app es una columna de 430px centrada, también en
   escritorio — el uso real es de pie, con una mano. */

.vista {
  max-width: var(--ancho); margin: 0 auto; min-height: 100svh;
  padding: calc(env(safe-area-inset-top, 0px) + 28px) 20px
           calc(var(--barra-total) + var(--esp-6));
}
/* La animación de entrada se pone al navegar, no siempre: si estuviera en
   .vista se volvería a disparar en cada tecla del buscador. */
.vista--entra { animation: entrada var(--dur-2) var(--curva) both; }
.vista--centro { display: grid; align-content: center; justify-items: center;
                 text-align: center; padding-bottom: var(--esp-8); }
@keyframes entrada { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

.encabezado { display: flex; align-items: baseline; justify-content: space-between; gap: var(--esp-3); }
.encabezado .num { font-size: .9375rem; font-weight: 500; color: var(--tinta-3); }
.sub { font-size: .9375rem; color: var(--tinta-3); margin-top: 4px; }

/* Los títulos de sección son la única «línea divisoria» de la interfaz. */
h2.seccion { font-size: .8125rem; font-weight: 640; letter-spacing: .015em;
             color: var(--tinta-3); margin: 36px 0 8px; }
.acotacion { font-size: .75rem; color: var(--tinta-3); line-height: 1.55; }

.volver { display: inline-flex; align-items: center; gap: 1px; min-height: 44px;
          margin-left: -8px; font-size: .9375rem; font-weight: 580; color: var(--mioo); }
.volver svg { width: 20px; height: 20px; fill: none; stroke: currentColor;
              stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

.marca { font-weight: 720; letter-spacing: -.05em; font-size: 2.75rem; line-height: 1; }
.marca i { font-style: normal; color: var(--mioo); }

/* === estados de un dato ================================================== */

.estado { display: inline-flex; align-items: center; gap: 5px;
          font-size: .75rem; font-weight: 620; letter-spacing: .01em; white-space: nowrap; }
.estado::before { content: ""; width: 5px; height: 5px; border-radius: 50%;
                  background: currentColor; flex: none; }
.estado--verificado { color: var(--verificado); }
.estado--inferido   { color: var(--inferido); }
.estado--pendiente  { color: var(--pendiente); }
.estado--retirado   { color: var(--retirado); }
.estado--sinsync    { color: var(--sinsync); }

/* === controles =========================================================== */

.boton {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 50px; padding: 0 22px; border: 0; border-radius: var(--r-lg);
  background: var(--mioo); color: var(--sobre-mioo);
  font: 600 1rem/1.2 var(--fuente); letter-spacing: -.008em;
  cursor: pointer; text-decoration: none;
  transition: transform var(--dur-1) var(--curva), opacity var(--dur-1) var(--curva);
}
.boton:hover { opacity: .92; text-decoration: none; }
.boton:active { transform: scale(.97); }
.boton[disabled] { opacity: .5; cursor: not-allowed; }
.boton--suave   { background: var(--superficie); color: var(--tinta); }
.boton--texto   { background: none; color: var(--mioo); min-height: 44px; padding: 0 10px; }
.boton--peligro { background: none; color: var(--peligro); min-height: 44px; padding: 0 10px; }
.boton--bloque  { width: 100%; min-height: 54px; }

/* Un icono dentro de un botón.
   Sin esta regla el <svg> no tiene tamaño propio —solo `viewBox`—, así que como
   elemento flexible se estira a lo que le deje la línea y se pinta con el `fill`
   negro por defecto en vez de con el trazo. «Escanear su código QR» medía 196px de
   alto en un iPhone 14 y empujaba 176px de formulario fuera de la pantalla: la hoja
   nacía con scroll.
   Todos los demás sitios que sacan un icono ya traían la suya —.fab, .barra a,
   .volver, .swipe__acciones, .escaner__cerrar—; el botón era el único que no, y por
   eso el fallo tenía un solo sitio donde verse. `flex: none` para que tampoco
   encoja cuando la etiqueta es larga. */
.boton svg { flex: none; width: 20px; height: 20px; fill: none; stroke: currentColor;
             stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* La diana de escanear: el objetivo grande de la hoja de guardar.
   Grande A PROPÓSITO, que no es lo mismo que grande por accidente. Antes lo era
   por accidente: el <svg> sin tamaño propio se estiraba a lo que le dejara su
   línea, así que el MISMO botón medía 196px de alto en un iPhone 14 y 136 en uno
   de 320 — dos tamaños, ninguno elegido, y ninguno reproducible. Aquí las
   medidas están escritas: mide lo mismo en todas partes.
   Es la vía rápida y por eso pesa más que el formulario que tiene debajo; el
   pulgar tiene que encontrarla sin buscarla. */
.boton--diana { min-height: 196px; padding: 20px 22px; gap: 20px;
                border-radius: var(--r-hoja); font-size: 1.0625rem; font-weight: 620;
                line-height: 1.3; }
/* La diana se pinta RELLENA, y es lo único de la app que lo hace.
   No es un descuido heredado: es la forma que el operador reconoce como «esto
   abre la cámara». Los cuatro trazos de esquina son abiertos, así que al
   rellenarlos el navegador los cierra por el camino corto y salen macizos; la
   recta del centro no tiene área y no se pinta. Ese es el dibujo, tal cual.
   `currentColor` y NUNCA un color fijo: así era antes —negro por defecto del
   navegador— y en el tema oscuro habría quedado negro sobre casi negro. Lo que se
   conserva es la forma, no el fallo que la producía.
   A 20px este mismo relleno son cuatro manchas ilegibles, por eso solo aquí: el
   resto de iconos siguen a trazo. */
.boton--diana svg { width: 128px; height: 128px; fill: currentColor; stroke: none; }
/* El acuse baja a .985, y no es un ajuste fino: la regla del sistema es viaje de
   BORDE constante (~1–2px), no escala constante. La diana heredaba el `.97` de
   `.boton`, pensado para 50px de alto; a 196 cada borde viajaba 3px y el objeto más
   grande de la app era también el que más se movía al tocarlo. Por eso el icono de
   la barra usa .86 (23px), el engranaje .9 (44), el fab .93 (58) y el botón .97 (50). */
.boton--diana:active { transform: scale(.985); }
.boton--diana span { text-align: left; }

/* El paso a la otra cara. Sin etiqueta visible: un código y una flecha dicen a
   dónde lleva mejor que dos palabras, y así deja de disputarle el renglón al
   título — que era justo lo que lo hacía verse apretado.
   Sin texto no hay nombre accesible, así que va en `aria-label`: sin él un lector
   de pantalla anuncia «botón» y se acabó. `min-width` igual en las dos caras para
   que al cruzar no cambie de tamaño bajo el dedo. */
.boton--paso { min-height: 44px; min-width: 68px; padding: 0 14px; gap: 2px;
               border-radius: var(--r-full); flex: none; }
.boton--paso svg { width: 20px; height: 20px; }
.boton--paso .paso__flecha { width: 15px; height: 15px; opacity: .6; }

.campo-texto, textarea, select {
  width: 100%; min-height: 52px; padding: 14px 16px;
  border: 1.5px solid transparent; border-radius: var(--r-lg);
  background: var(--superficie); color: var(--tinta);
  font: inherit; font-size: 1.0625rem;
  transition: border-color var(--dur-1) var(--curva), background var(--dur-1) var(--curva);
}
textarea { resize: none; line-height: 1.45; }
.campo-texto:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--mioo); background: var(--fondo);
}
::placeholder { color: var(--tinta-3); opacity: 1; }
label { display: block; font-size: .8125rem; font-weight: 580; color: var(--tinta-2);
        margin: 0 0 6px 2px; }
.grupo + .grupo { margin-top: var(--esp-4); }

.buscador { position: relative; margin: var(--esp-4) 0; }
.buscador .campo-texto { min-height: 48px; padding-left: 46px; border-radius: var(--r-full); }
.buscador svg { position: absolute; left: 16px; top: 50%; translate: 0 -50%;
                width: 19px; height: 19px; fill: none; stroke: var(--tinta-3);
                stroke-width: 1.9; stroke-linecap: round; }

.segmentos { display: flex; gap: 8px; flex-wrap: wrap; }
.segmento { flex: 1; min-width: 78px; min-height: 46px; border: 0; border-radius: var(--r-md);
            background: var(--superficie); color: var(--tinta-2);
            font: 580 .9375rem/1.2 var(--fuente); cursor: pointer;
            transition: background var(--dur-1) var(--curva), color var(--dur-1) var(--curva); }
.segmento--activo { background: var(--mioo-suave); color: var(--mioo); font-weight: 640; }

.avatar { width: 44px; height: 44px; border-radius: var(--r-full); flex: none;
          display: grid; place-items: center; background: var(--superficie-2);
          color: var(--tinta-2); font-weight: 640; font-size: .8125rem; }
.avatar--xl { width: 64px; height: 64px; font-size: 1.125rem; }
/* La foto ocupa el mismo hueco que las iniciales, así que cambiar de una a otra no
   mueve nada de su alrededor. */
.avatar--foto { object-fit: cover; background: var(--superficie-2); }

.vacio { color: var(--tinta-3); text-align: center; }
.vacio h2 { font-size: 1.375rem; font-weight: 660; letter-spacing: -.02em;
            color: var(--tinta); margin-bottom: 8px; }
.vacio p { font-size: .9375rem; max-width: 30ch; margin: 0 auto; }

/* Sin conexión no es un error: es el modo normal de una expo. Se informa con
   una pastilla discreta, no con una alarma roja. */
.sin-red { display: inline-flex; align-items: center; gap: 7px; min-height: 32px;
           padding: 4px 14px; border-radius: var(--r-full);
           background: var(--superficie); color: var(--tinta-2);
           font-size: .75rem; font-weight: 580; }
.sin-red::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
                   background: var(--sinsync); flex: none; }

.mono { font-family: var(--mono); font-size: .8125rem; }
.chip-mono { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px;
             border-radius: var(--r-full); background: var(--superficie);
             font-family: var(--mono); font-size: .8125rem; color: var(--tinta-2);
             word-break: break-word; }

.aviso { padding: 14px 16px; border-radius: var(--r-lg); background: var(--superficie);
         font-size: .875rem; color: var(--tinta-2); line-height: 1.45; text-align: left; }

/* === filas de personas y lugares =========================================
   Sin tarjetas: la fila vive sobre el fondo y solo se enciende al tocarla.
   minmax(0,1fr) en la columna de texto — sin ese 0, una pista 1fr tiene
   min-width:auto y un nombre largo empuja la fila fuera del contenedor en vez
   de recortarse: la elipsis no llegaría a dispararse nunca. */

.fila-p { display: grid; grid-template-columns: 44px minmax(0,1fr) auto;
          gap: 14px; align-items: center; min-height: 64px; width: 100%;
          margin: 0 -12px; padding: 8px 12px; border-radius: var(--r-lg);
          border: 0; background: none; color: inherit; font: inherit; text-align: left;
          text-decoration: none; cursor: pointer;
          transition: background var(--dur-1) var(--curva); }
.fila-p--simple { grid-template-columns: minmax(0,1fr) auto; min-height: 58px; }
.fila-p:hover { text-decoration: none; background: var(--superficie); }
.fila-p:active { background: var(--superficie-2); }
.fila-p__tx { min-width: 0; }
.fila-p__n { display: block; font-size: 1.0625rem; font-weight: 580; letter-spacing: -.012em;
             white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fila-p__s { display: block; font-size: .8125rem; color: var(--tinta-3); margin-top: 1px;
             white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fila-p__m { display: flex; flex-direction: column; align-items: flex-end; gap: 3px;
             font-size: .75rem; color: var(--tinta-3); white-space: nowrap; }

/* === datos de identidad ================================================== */

.datos { margin-top: 2px; }
.dato { display: grid; grid-template-columns: minmax(0,1fr) auto; column-gap: 12px;
        align-items: baseline; padding: 9px 0; }
.dato__k { font-size: .75rem; font-weight: 580; color: var(--tinta-3); letter-spacing: .01em; }
.dato__v { grid-column: 1; font-size: 1.0625rem; font-weight: 480; margin-top: 2px;
           white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dato .estado { grid-column: 2; grid-row: 1; justify-self: end; }
.dato--retirado .dato__v { color: var(--retirado); text-decoration: line-through;
                           text-decoration-thickness: 1px; }

.etiquetas { display: flex; gap: 8px; flex-wrap: wrap; }
.etiqueta { position: relative; display: inline-flex; align-items: center; min-height: 38px;
            padding: 0 15px; border-radius: var(--r-full); border: 0;
            background: var(--superficie); color: var(--tinta-2);
            font: 580 .8125rem/1 var(--fuente); white-space: nowrap; cursor: pointer;
            text-decoration: none; transition: background var(--dur-1) var(--curva); }
/* El objetivo táctil llega a 46px sin que la pastilla crezca.
   `pointer-events: none` NO es opcional: sin él, esta capa transparente se pinta
   encima de todo lo que haya dentro de la pastilla y se queda los toques. Con la
   etiqueta editable —que lleva dos botones dentro— eso hacía imposible borrarla:
   el navegador entregaba el toque al span, no a la equis. */
.etiqueta::after { content: ""; position: absolute; inset: -4px; border-radius: inherit;
                   pointer-events: none; }
.etiqueta--activa { background: var(--mioo-suave); color: var(--mioo); }

/* Editable: la equis vive DENTRO de la pastilla. Como pastilla aparte parecía otra
   etiqueta que se llamaba «×», y con tres o cuatro palabras la fila era un
   rompecabezas de píldoras sueltas. */
.etiqueta--edit { padding-right: 6px; gap: 2px; }
.etiqueta__x { position: relative; display: grid; place-items: center;
               width: 26px; height: 26px; flex: none;
               margin-left: 2px; border: 0; border-radius: 50%; background: none;
               color: var(--tinta-3); font: 400 1rem/1 var(--fuente); cursor: pointer;
               transition: background var(--dur-1) var(--curva), color var(--dur-1) var(--curva); }
/* La equis pinta 26px pero se toca en 44: el pulgar necesita eso y la pastilla no
   puede crecer tanto sin romper la fila. */
.etiqueta__x::after { content: ""; position: absolute; inset: -9px; border-radius: 50%; }
.etiqueta__x:hover { background: var(--superficie-2); color: var(--peligro); }

/* Añadir es una acción, no una etiqueta: se distingue con un contorno en vez de
   competir con las palabras de al lado. */
.etiqueta--nueva { background: none; color: var(--tinta-3);
                   box-shadow: inset 0 0 0 1.5px var(--linea); font-weight: 620; }
.etiqueta--nueva:hover { color: var(--mioo); box-shadow: inset 0 0 0 1.5px var(--mioo); }

/* === historial =========================================================== */

.mes { font-size: .8125rem; font-weight: 640; color: var(--tinta-3); margin: 30px 0 4px; }
.evento { display: grid; grid-template-columns: 14px minmax(0,1fr); column-gap: 12px; padding: 12px 0; }
.evento__pto { width: 7px; height: 7px; border-radius: 50%; background: var(--tinta-3);
               margin-top: 7px; justify-self: center; }
.evento--mioo .evento__pto       { background: var(--mioo); }
.evento--verificado .evento__pto { background: var(--verificado); }
.evento--inferido .evento__pto   { background: var(--inferido); }
.evento--retirado .evento__pto   { background: var(--retirado); }
.evento__cuando { font-size: .75rem; color: var(--tinta-3); }
.evento__que { font-size: 1rem; font-weight: 580; letter-spacing: -.01em; }
.evento__det { font-size: .9375rem; color: var(--tinta-2); margin-top: 1px;
               white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* === barra inferior y captura ============================================
   Lo que se toca seguido va abajo, al alcance del pulgar. La altura suma la
   safe area del iPhone (~34px): sin sumarla al alto, y como todo es
   border-box, se comería el espacio de los enlaces y la barra se vería
   cortada por la mitad. */

.barra { position: fixed; bottom: 0; left: 50%; translate: -50% 0;
         width: 100%; max-width: var(--ancho); height: var(--barra-total);
         padding-bottom: env(safe-area-inset-bottom, 0px);
         display: flex; align-items: stretch; z-index: 20;
         background: color-mix(in srgb, var(--fondo) 86%, transparent);
         -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
         border-top: 1px solid color-mix(in srgb, var(--linea) 70%, transparent); }
.barra a { flex: 1; display: flex; flex-direction: column; align-items: center;
           justify-content: center; gap: 3px; font-size: .6875rem; font-weight: 540;
           color: var(--tinta-3); text-decoration: none;
           transition: color var(--dur-1) var(--curva); }
.barra a:hover { text-decoration: none; }
/* Acuse instantáneo bajo el dedo.
   El icono se hunde en cuanto se toca, sin esperar a que la ruta acabe su trabajo
   —de 24 a 91 ms medidos con la CPU de un teléfono—. No acelera nada; hace que el
   hueco deje de parecer que el toque se perdió, que es lo que se sentía.
   Va en el `svg` y no en el enlace para no mover también la etiqueta. */
.barra a svg { transition: transform var(--dur-1) var(--curva), color var(--dur-1) var(--curva); }
.barra a:active svg { transform: scale(.86); }
.barra a svg { width: 23px; height: 23px; fill: none; stroke: currentColor;
               stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.barra a[aria-current="page"] { color: var(--mioo); font-weight: 640; }
/* El logotipo de la barra solo existe en escritorio. En el teléfono ocuparía la
   altura de un elemento a cambio de nada: ya sabes en qué app estás. */
.barra__logo { display: none; }

.fab { position: fixed; z-index: 15;
       right: max(20px, calc(50% - (var(--ancho) / 2) + 20px));
       bottom: calc(var(--barra-total) + 20px);
       width: 58px; height: 58px; border-radius: var(--r-full); border: 0;
       display: grid; place-items: center;
       background: var(--mioo); color: var(--sobre-mioo);
       box-shadow: var(--sombra-flot); cursor: pointer;
       transition: transform var(--dur-1) var(--curva); }
.fab:active { transform: scale(.93); }
.fab svg { width: 26px; height: 26px; stroke: currentColor; stroke-width: 2;
           fill: none; stroke-linecap: round; }

/* === hoja inferior ======================================================= */

.telon { position: fixed; inset: 0; background: rgba(0, 0, 0, .5); z-index: 30;
         animation: aparecer var(--dur-2) var(--curva) both; }

/* `--teclado` lo mantiene JavaScript leyendo visualViewport. En Safari de iPhone la
   barra de direcciones y el teclado tapan el fondo de la pantalla sin que
   env(safe-area-inset-bottom) se entere: por eso el botón «Guardar» quedaba debajo
   de la barra del navegador. La hoja se ancla al viewport VISIBLE, no al de la
   maqueta. */
.hoja { position: fixed; left: 50%; bottom: var(--teclado, 0px); translate: -50% 0; z-index: 31;
        width: 100%; max-width: var(--ancho);
        /* 96 y no 92: con la diana de escanear puesta, la hoja de guardar mide
           725px y esos cuatro puntos son 35px en un teléfono de 890 — la
           diferencia entre caber y nacer con scroll. Lo que se cede es telón
           visible arriba, que solo tiene que bastar para leer «esto es una hoja
           que se puede bajar»; 4svh siguen siendo 36px en ese mismo teléfono. */
        max-height: calc(96svh - var(--teclado, 0px));
        display: flex; flex-direction: column;
        background: var(--fondo); border-radius: var(--r-hoja) var(--r-hoja) 0 0;
        box-shadow: var(--sombra-flot);
        /* La hoja no hace scroll: lo hace su interior. Así el gesto vertical sobre
           el borde es siempre arrastre y nunca se lo queda el navegador. */
        overflow: hidden; touch-action: none;
        /* Capa propia: sin esto, la sombra de 40px de difuminado se vuelve a
           rasterizar en cada fotograma mientras se arrastra. */
        will-change: transform;
        animation: subir var(--dur-2) var(--curva) both; }
/* Mientras se va no se puede volver a agarrar ni tocar nada de dentro. */
.hoja--cerrando { pointer-events: none; }
.hoja__scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; touch-action: pan-y;
                padding: 0 20px calc(var(--esp-5) + env(safe-area-inset-bottom, 0px));
                overscroll-behavior: contain; }
/* Un tirador de 5px no se agarra con el pulgar: lo que se agarra es esta banda. */
.hoja__agarre { flex: none; padding: 12px 0 10px; display: grid; place-items: center;
                background: var(--fondo); cursor: grab; user-select: none; }
.hoja__agarre:active { cursor: grabbing; }
.hoja__tirador { width: 36px; height: 5px; border-radius: var(--r-full);
                 background: var(--superficie-2); }
.hoja__titulo { font-size: 1.375rem; font-weight: 680; letter-spacing: -.02em; margin: 2px 0 4px; }
/* Título y, a su derecha, el paso a la otra cara de la hoja. En una fila y no en
   dos: esta hoja tiene que caber entera sin scroll, y un renglón suelto para un
   botón cuesta 44px de los que no sobran. `center` y no `baseline` porque lo que
   se alinea es una pastilla con un texto, no dos textos. */
.hoja__cabeza { display: flex; align-items: center; justify-content: space-between;
                gap: var(--esp-4); margin: 0 0 var(--esp-3); }
.hoja__cabeza .hoja__titulo { margin: 0; min-width: 0; }
/* El título recibe el foco al cambiar de cara, para que un lector de pantalla
   anuncie la sección nueva. Recibirlo no es pulsarlo: sin anillo. */
.hoja__titulo:focus { outline: none; }

/* Las dos caras de la hoja.
   En flujo normal —solo una visible, la otra con `hidden`— salvo mientras cruzan,
   que es el único momento en que se superponen para poder deslizarse una sobre
   otra. Fuera del cruce NO son absolutas a propósito: si lo fueran, el contenedor
   no tendría alto propio y habría que sostenerlo a mano para siempre. */
.caras { position: relative; }
.caras--cruzando { overflow: hidden; }
.caras--cruzando > .cara { position: absolute; inset: 0 0 auto 0; width: 100%; }
/* Salir tiene animación propia. Desaparecer de golpe hace que el ojo no sepa si
   la hoja se cerró o si algo se rompió. */
.hoja--saliendo { animation: bajar var(--dur-2) var(--curva) forwards; }
.telon--saliendo { animation: desaparecer var(--dur-2) var(--curva) forwards; }

/* La vista de debajo se apaga en vez de taparse del todo: se sigue viendo de
   quién es la nota que estás escribiendo.
   Sin `filter`: un filtro a pantalla completa se recompone en CADA fotograma del
   arrastre, y era lo que hacía que la hoja se moviera a tirones. La opacidad sola
   la resuelve el compositor sin repintar nada. */
.detras { opacity: .45; pointer-events: none; }
.detras .cabeza { display: flex; gap: 16px; align-items: center;
                  max-width: var(--ancho); margin: 0 auto;
                  padding: calc(env(safe-area-inset-top, 0px) + 28px) 20px 0; }

@keyframes subir { from { transform: translateY(100%); } to { transform: none; } }
@keyframes bajar { to { transform: translateY(100%); } }
@keyframes aparecer { from { opacity: 0; } to { opacity: 1; } }
@keyframes desaparecer { to { opacity: 0; } }

@media (min-width: 640px) {
  .hoja { bottom: auto; top: 50%; translate: -50% -50%; width: min(440px, 92vw);
          max-height: 90svh; border-radius: var(--r-hoja); touch-action: auto;
          animation: entrada var(--dur-2) var(--curva) both; }
  .hoja__scroll { padding-top: 20px; }
  .hoja__agarre { display: none; }
  .hoja--saliendo { animation: desaparecer var(--dur-2) var(--curva) forwards; }
}

/* === escritorio ==========================================================
   La app se diseñó para el pulgar y eso NO se toca: todo lo de aquí abajo vive
   dentro de la consulta de medios, así que un teléfono no ve ni una línea.
   Cambiar la maqueta común «para que sirva en las dos» habría acabado empeorando
   la que de verdad se usa.
   Lo que cambia en una pantalla grande es solo el chasis:
     · la barra de abajo pasa a ser una columna a la izquierda —el pulgar no llega
       al borde inferior de un monitor, el ratón llega a todas partes igual—;
     · la columna de contenido respira un poco más, pero sigue siendo UNA columna:
       una libreta de personas se lee en vertical, y estirarla a 1400 px de ancho
       daría renglones que hay que recorrer con la cabeza;
     · el resto se queda centrado en el hueco que queda, sin cuentas: el margen
       lateral se lo lleva el contenedor, no la columna.
   Las hojas ya eran diálogos centrados desde los 640 px; eso no se repite aquí. */

@media (min-width: 900px) {
  :root {
    --lateral: 250px;
    --ancho: 600px;
    /* Ya no hay barra abajo, así que el hueco que reservaba sobra. */
    --barra-total: 0px;
  }

  /* El margen se lo queda el contenedor y no `.vista`, que así sigue centrándose
     sola con su `margin: 0 auto`. La clase la pone `render()` solo cuando dibuja
     la barra: la pantalla de entrada no la tiene y no debe descuadrarse. */
  #app.con-barra { padding-left: var(--lateral); }

  .vista { padding-top: 56px; padding-bottom: var(--esp-8); }

  .barra {
    top: 0; bottom: 0; left: 0; translate: none;
    width: var(--lateral); max-width: none; height: auto;
    padding: 26px 14px 20px;
    flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 2px;
    background: var(--fondo);
    /* Sin desenfoque: aquí no hay contenido pasando por debajo, y un filtro a
       pantalla completa se recompone en cada scroll para no enseñar nada. */
    -webkit-backdrop-filter: none; backdrop-filter: none;
    border-top: 0; border-right: 1px solid var(--linea);
  }
  .barra__logo { display: block; width: 86px; height: auto; margin: 2px 10px 24px; }
  .barra a {
    flex: none; flex-direction: row; justify-content: flex-start; gap: 12px;
    min-height: 46px; padding: 0 12px; border-radius: var(--r-md);
    font-size: .9375rem; font-weight: 560;
    transition: background var(--dur-1) var(--curva), color var(--dur-1) var(--curva);
  }
  .barra a:hover { background: var(--superficie); color: var(--tinta); }
  .barra a[aria-current="page"] { background: var(--mioo-suave); }
  .barra a svg { width: 21px; height: 21px; }

  /* El botón flotante se ancla al borde de la COLUMNA, no al de la pantalla: en un
     monitor ancho acabaría a un palmo del contenido, y un botón que no está donde
     miras es un botón que no se ve. Mismo margen de 20 px que en el teléfono. */
  .fab {
    bottom: 32px;
    right: max(24px, calc((100vw - var(--lateral) - var(--ancho)) / 2 + 20px));
  }

  /* Con ratón el objetivo no tiene que medir 44 px, pero se dejan igual: el mismo
     usuario abre la app en el teléfono y en el portátil, y que un botón cambie de
     sitio y de tamaño según el aparato es de las cosas que hacen dudar. */
}

/* === deslizar una fila para archivar o eliminar ==========================
   Como en las apps de mensajería: la fila se mueve con el dedo y deja ver las
   acciones detrás. No hay menú oculto ni pulsación larga que nadie descubre. */

.swipe { position: relative; overflow: hidden; border-radius: var(--r-lg); }
/* Ocultas del todo hasta que empieza el gesto. Con `overflow:hidden` y esquinas
   redondeadas asomaban por las curvas y parecían el borde de una tarjeta que este
   diseño no tiene. */
.swipe__acciones { position: absolute; inset: 0 0 0 auto; display: flex;
                   visibility: hidden; }
.swipe--tocado .swipe__acciones { visibility: visible; }
.swipe__acciones button { border: 0; width: 84px; display: grid; place-items: center; gap: 4px;
                          font: 580 .75rem/1.2 var(--fuente); color: #fff; cursor: pointer; }
.swipe__acciones svg { width: 20px; height: 20px; fill: none; stroke: currentColor;
                       stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.swipe__archivar { background: var(--tinta-3); }
.swipe__eliminar { background: var(--peligro); }
.swipe__frente { position: relative; background: var(--fondo); will-change: transform; }
.swipe--animando .swipe__frente { transition: transform var(--dur-2) var(--curva); }

/* === escáner de QR =======================================================
   A pantalla completa y fuera de la columna de 430px: apuntar una cámara es lo
   contrario de leer, y cuanto más grande sea el visor menos hay que acercarse. */

.escaner { position: fixed; inset: 0; z-index: 60; background: #000; overflow: hidden; }
.escaner__video { width: 100%; height: 100%; object-fit: cover; }
/* La mira no recorta nada: el código se lee de todo el cuadro. Es una guía para
   que la persona sepa dónde apuntar, y por eso no tiene fondo. */
.escaner__mira { position: absolute; top: 50%; left: 50%; translate: -50% -50%;
                 width: min(66vw, 280px); aspect-ratio: 1;
                 border: 2px solid rgba(255, 255, 255, .9); border-radius: 24px;
                 box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .45); }
.escaner__ayuda { position: absolute; left: 0; right: 0;
                  bottom: calc(env(safe-area-inset-bottom, 0px) + 44px);
                  text-align: center; color: #fff; font-size: .9375rem; font-weight: 560;
                  text-shadow: 0 1px 12px rgba(0, 0, 0, .8); padding: 0 24px; }
.escaner__cerrar { position: absolute; top: calc(env(safe-area-inset-top, 0px) + 14px); right: 14px;
                   width: 44px; height: 44px; border: 0; border-radius: var(--r-full);
                   background: rgba(0, 0, 0, .5); color: #fff; display: grid; place-items: center;
                   cursor: pointer; }
.escaner__cerrar svg { width: 22px; height: 22px; fill: none; stroke: currentColor;
                       stroke-width: 2.2; stroke-linecap: round; }

/* === perfil y QR ========================================================= */
/* Blanco fijo pase lo que pase con el tema: un lector de QR necesita el
   contraste del código, no el de la interfaz. */
/* La tarjeta propia dentro de la hoja «Que te guarden»: enseña lo que se lleva
   quien escanea, con la misma foto y los mismos campos del perfil público.
   Fondo blanco fijo, igual que `.qr-caja`: las dos son la cosa que se ENSEÑA a
   otra persona, y tienen que verse igual con el tema claro y con el oscuro. */
/* El borde no es adorno: sin él, en el tema claro la tarjeta NO SE VE.
   `--fondo` es #FFFFFF en claro y #F9FFFE en el tema mioo, y una tarjeta blanca
   sobre fondo blanco se lee como texto suelto con una raya en medio. Se vio
   mirándola, no leyéndola: en oscuro estaba perfecta. Y va aquí, con un color fijo,
   por lo mismo que el fondo — esto se enseña, y tiene que verse igual en los tres
   temas. Un borde y no una sombra: en este proyecto la sombra es de lo que flota. */
.tarjeta-mia { background: #FFFFFF; color: #111114; border-radius: 20px;
               border: 1px solid #E3E3E9; padding: 16px 18px; }
/* Foto a la izquierda y nombre a su derecha, no apilados.
   Apilados y centrados eran 156px —102 de foto, 26 de nombre, 28 de cargo— para
   decir tres cosas cortas, y esta hoja no cabía en ningún teléfono por 172px. En
   fila son 72: el alto lo pone la foto y el texto va dentro. Es además la forma de
   una tarjeta de papel, que es lo que esto es. */
.tarjeta-mia__quien { display: flex; align-items: center; gap: 14px; }
.tarjeta-mia__dice { min-width: 0; }
/* Colores fijos también aquí: `.avatar` sin foto toma `--superficie-2`, que en el
   tema oscuro es casi negro y sobre la tarjeta blanca se veía como un agujero. */
.tarjeta-mia__foto { width: 72px; height: 72px; font-size: 1.375rem;
                     background: #ECECF1; color: #52525C; }
.tarjeta-mia img.tarjeta-mia__foto { object-fit: cover; }
/* Un nombre largo se parte en dos renglones antes que empujar la foto: `min-width:0`
   arriba deja que la caja de texto se encoja, que es lo que un flex no hace solo. */
.tarjeta-mia__nombre { font-size: 1.3125rem; font-weight: 660; letter-spacing: -.02em;
                       margin: 0; line-height: 1.2; overflow-wrap: anywhere; }
.tarjeta-mia__rol { margin: 3px 0 0; font-size: .9375rem; line-height: 1.3;
                    color: #52525C; overflow-wrap: anywhere; }
.tarjeta-mia__datos { margin: 12px 0 0; }
/* Etiqueta y valor en el MISMO renglón, no uno debajo del otro.
   Uno debajo del otro son 72px por campo; al lado, 40. Con teléfono y correo eso
   son 64px que la hoja recupera, y no se pierde nada: «Teléfono» a la izquierda y
   el número a la derecha se lee igual de rápido. */
.tarjeta-mia__datos .dato { grid-template-columns: auto minmax(0, 1fr);
                            column-gap: 14px; align-items: baseline; padding: 7px 0; }
/* La línea separa los campos entre sí, no del nombre: el primero queda pegado al
   bloque de identidad, que es de lo que habla. */
.tarjeta-mia__datos .dato + .dato { border-top: 1px solid #ECECEF; }
.tarjeta-mia__datos .dato__k { grid-column: 1; grid-row: 1; color: #6E6E79; }
/* Sin recorte: `.dato__v` corta con puntos suspensivos, que está bien en una lista
   pero no aquí. Esta es la tarjeta que enseñas para que alguien copie tu correo, y
   un correo cortado no se puede copiar. Cabe en dos líneas antes que perderse. */
/* `margin-inline-start: 0` no es cosmético: un <dd> nace con 40px de sangría por
   defecto del navegador, y esos 40 salían de la columna del valor. Un correo largo
   partía un renglón antes de lo necesario por una regla que nadie escribió. Se vio
   midiendo la columna —247px de 287 disponibles—, no mirándola. El <dl>/<dt>/<dd> se
   queda: son pares nombre-valor y esa es su etiqueta; lo que sobra es la sangría. */
.tarjeta-mia__datos .dato__v { grid-column: 2; grid-row: 1;
                               margin-top: 0; margin-inline-start: 0;
                               font-size: 1rem; text-align: right;
                               white-space: normal; overflow-wrap: anywhere; }
.tarjeta-mia__vacia { margin: 12px 0 0; color: #52525C; }

.qr-caja { background: #FFFFFF; color: #111114; padding: 18px; border-radius: 20px;
           display: inline-block; }
.qr-caja img { display: block; width: 100%; height: auto; max-width: 240px; }

/* El bloque del código. Estos valores estaban en línea dentro de `codigo.js`, y un
   estilo en línea gana sobre la hoja de estilos: para apretarlo dentro de una hoja
   habría hecho falta `!important`. Aquí la regla de la hoja gana por especificidad
   y sola, que es como debe ganar. Los números son los mismos que había. */
.codigo { text-align: center; }
.codigo__url { margin-top: 12px; font-weight: 580; }
.codigo__acciones { display: flex; gap: 10px; justify-content: center;
                    margin-top: 12px; flex-wrap: wrap; }
.codigo__acciones .boton { min-height: 44px; }
.codigo__mas { margin-top: 12px; }
.codigo__msg { margin-top: 10px; }

/* El código, DENTRO de una hoja, se aprieta.
   El mismo bloque vive en el perfil, que es una página y hace scroll porque para eso
   está; una hoja no, tiene que caber. De ahí que la regla cuelgue de `.hoja` y no de
   una clase nueva: la diferencia real es esa, estar en algo de alto limitado.

   El QR se mide en `svh` para que se ajuste al teléfono en vez de a un número fijo:
   240px en uno grande, 160 en un SE. El suelo son 150px —a 3x eso son 450 puntos de
   pantalla, de sobra para cualquier lector—; por debajo prefiere que la hoja haga
   scroll antes que dar un código que no se lee. */
/* Mismo borde que la tarjeta, y solo dentro de la hoja: ahí las dos van una encima
   de otra y con una sola perfilada se notaba el desparejo. En el perfil la caja del
   QR se queda como estaba — allí no hay tarjeta con la que compararla. */
.hoja .qr-caja { padding: 14px; border: 1px solid #E3E3E9; }
.hoja .qr-caja img { width: clamp(150px, 22svh, 240px); }
.hoja .codigo__url,
.hoja .codigo__acciones,
.hoja .codigo__mas,
.hoja .codigo__msg { margin-top: 8px; }
/* La nota de la hoja: un renglón entre la tarjeta y el código, y los márgenes
   contados. Eran 18 y 16. */
.cara__nota { margin: 12px 0; }

/* PANTALLAS CORTAS.
   Con la tarjeta ya en fila, esta hoja cabe de sobra en un iPhone grande —117px
   libres en un 14 Pro Max instalado como app— pero se quedaba a 10px en un 13 mini
   y hacía scroll por 27 en un 15 con la barra de Safari puesta. Diez píxeles no son
   caber: un nombre que pase a dos renglones se los come.

   Así que por debajo de 820 de alto todo se aprieta un punto. Solo lo de esta hoja:
   `.hoja__cabeza` y el relleno de `.hoja__scroll` los comparten TODAS las hojas y no
   se tocan desde aquí. Medido: pasa de +10 a +68 en el mini y de -27 a +31 en el 15. */
@media (max-height: 820px) {
  .tarjeta-mia { padding: 12px 14px; }
  .tarjeta-mia__quien { gap: 12px; }
  .tarjeta-mia__foto { width: 56px; height: 56px; font-size: 1.125rem; }
  .tarjeta-mia__nombre { font-size: 1.1875rem; }
  .tarjeta-mia__datos { margin-top: 8px; }
  .tarjeta-mia__datos .dato { padding: 5px 0; }
  .cara__nota { margin: 8px 0; }
  .hoja .qr-caja { padding: 10px; }
  .hoja .codigo__url { font-size: .9375rem; }
}
/* Y por debajo de 700 se cae «Ver cómo te ven ›».
   Es la única cosa de esta hoja que se quita en vez de encogerse, y se quita porque
   es la única que está en otro sitio: el mismo bloque, con el mismo enlace, está en
   tu perfil. Lo que NO se quita es el código, ni la tarjeta, ni copiar y compartir —
   eso es para lo que se abre la hoja. Sin esto un iPhone SE se queda a -68. */
@media (max-height: 700px) {
  .hoja .codigo__mas { display: none; }
}

/* === documentos largos =================================================== */

.doc h2 { font-size: 1.1875rem; font-weight: 660; letter-spacing: -.018em; margin: 34px 0 10px; }
.doc p, .doc li { font-size: .9375rem; line-height: 1.65; color: var(--tinta-2); max-width: 62ch; }
.doc ul { margin: 0; padding-left: 20px; }
.doc li + li { margin-top: 8px; }
.doc b { color: var(--tinta); font-weight: 620; }
.plantilla { padding: 14px 16px; border-radius: var(--r-lg); background: var(--superficie);
             font-size: .875rem; line-height: 1.5; color: var(--tinta-2); max-width: 62ch; }
.plantilla b { color: var(--pendiente); }

/* === perfil público (servido sin JavaScript) ============================= */

body.publico { display: grid; place-items: center; min-height: 100svh; padding: 24px; }
body.publico .perfil { width: min(var(--ancho), 100%); text-align: center; }

/* El vídeo del perfil público.
   Vertical y centrado, entre el nombre y los datos: es una presentación, y
   presentarse va antes que dar el teléfono. Alto acotado en `svh` para que en una
   pantalla corta no empuje los botones fuera — un perfil que hay que bajar para
   encontrar «Guardar en mis contactos» falla en lo único que se le pide.
   `contain` sobre fondo negro: el archivo se enseña entero, venga con la
   proporción que venga. */
/* La foto en el público es más grande que en cualquier lista: aquí es la cara de
   alguien a quien acabas de conocer y a quien intentas reconocer, no un adorno de
   fila. `display: block` + `margin: auto` porque `.avatar` es inline-grid y no se
   centra solo. */
body.publico .avatar--xl { width: 104px; height: 104px; font-size: 1.75rem;
                           display: block; }
body.publico img.avatar--xl { object-fit: cover; }

body.publico .video-p { margin: 22px auto 4px; width: min(230px, 62%); }
body.publico .video-p__pieza { display: block; width: 100%; max-height: 46svh;
                               aspect-ratio: 9 / 16; object-fit: contain;
                               background: #0B0B0C; border-radius: var(--r-lg); }
