/* styles.css — Relaciones, rediseño limpio y minimalista: fondo cálido casi blanco, tinta
   casi negra, un único acento (terracota), Space Grotesk para titulares e Inter para todo
   lo demás — sans en toda la interfaz, sin serifs. Cumple el contrato del sitio
   (docs/WEBSITE.md): los tokens de abajo son los que lee cualquier página de cualquier
   módulo; los primitivos vienen de /base.css. */

:root {
	/* Escala de capas. Toda la app se apila con ESTOS seis valores y ninguno suelto: los
	   números elegidos uno a uno acaban peleándose, y averiguar por qué algo sale detrás
	   de otra cosa cuesta más que decidirlo aquí una vez. De abajo a arriba: lo que se
	   pega al borde, la barra de navegación, lo que flota sobre el contenido, un visor a
	   pantalla completa, la barra que se abre DENTRO de un visor, y el aviso que tapa
	   cualquier cosa. */
	--z-sticky: 10;
	--z-nav: 20;
	--z-flotante: 30;
	--z-visor: 40;
	--z-barra: 50;
	--z-aviso: 60;
	/* El mensaje de error, por encima de todo: si algo falla con una hoja o un visor
	   abierto, es justo cuando hay que verlo. */
	--z-toast: 70;

	/* El ancho del menú cuando se va al lateral, en un ordenador. Está aquí y no dentro de
	   la media query porque lo usan DOS reglas —el menú y el margen del contenido— y si
	   cada una llevara su número, el día que uno cambie quedaría una franja muerta. */
	--ancho-menu: 13.5rem;

	/* El ancho de la COLUMNA de una pantalla de la app. Estaba escrito a mano en cada
	   página —34rem en seis, 36 en la del calendario— y ensancharlas era ir fichero por
	   fichero. En un móvil ninguno de esos topes se llega a alcanzar (una pantalla de
	   teléfono son unos 24rem), así que el número solo se nota en un ordenador: por eso el
	   valor de escritorio vive abajo, en la media query, y no repetido aquí. */
	--ancho-app: 34rem;

	/* Escala tipográfica. Había veinte tamaños distintos para siete pantallas — nadie ve
	   la diferencia entre 0,8 y 0,82rem, pero sí se percibe el descuido. Seis pasos. */
	--txt-xs: 0.72rem;
	--txt-s: 0.82rem;
	--txt-m: 0.95rem;
	--txt-l: 1.1rem;
	--txt-xl: 1.4rem;
	--txt-titulo: 2rem;

	/* Espaciado, misma idea: cuatro pasos en vez de doce valores a ojo. */
	--sp-xs: 0.3rem;
	--sp-s: 0.6rem;
	--sp-m: 1rem;
	--sp-l: 1.6rem;

	--bg: #FAF9F6;
	--text: #18160F;
	--accent: #C52C2B;
	--font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

	--surface: #FFFFFF;
	--line: rgba(24, 22, 15, 0.09);
	--muted: #86807A;
	--accent-contrast: #FFFFFF;
	--accent-text: #A32322;
	--accent-soft: rgba(197, 44, 43, 0.08);
	--tint: rgba(197, 44, 43, 0.07);
	--font-display: "Space Grotesk", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	--radius: 16px;
	--radius-sm: 10px;
	--radius-control: 10px;
	--wrap: 74rem;
	--shadow: 0 1px 2px rgba(24, 22, 15, 0.04), 0 12px 28px -10px rgba(24, 22, 15, 0.14);
	--ring: 0 0 0 4px rgba(197, 44, 43, 0.18);
	--ok: #2F8F5B;
	--warn: #B8862B;
	--bad: #C0392B;
}

/* ---- Modo oscuro ---------------------------------------------------------------------
   Sigue al sistema: a las doce de la noche el móvil ya está en oscuro, y abrir el chat con
   un fondo blanco es un fogonazo. No hay interruptor propio a propósito — el que ya has
   elegido en el móvil es el que vale, y un ajuste más es una decisión más que tomar.
   Se cambian los TOKENS, no los estilos: como toda la app pinta con var(--…), cambiar la
   paleta cambia las 1.900 líneas de golpe. Lo único que hay que repasar a mano son los
   sitios donde alguien escribió un color en crudo, y están todos aquí abajo.
   `color-scheme` es lo que hace que los controles del sistema —el teclado del campo, las
   barras de scroll, los desplegables— salgan también oscuros. */
:root { color-scheme: light; }
@media (prefers-color-scheme: dark) {
	:root {
		color-scheme: dark;
		/* Ni negro puro ni gris azulado: el mismo tono cálido de la app, apagado. El negro
		   absoluto sobre OLED hace que el texto vibre al desplazar. */
		--bg: #15130F;
		--text: #F2EFE8;
		--surface: #1F1C17;
		--line: rgba(242, 239, 232, 0.12);
		--muted: #9B948A;
		/* El acento sube de luminosidad: el rojo de día se apaga sobre un fondo oscuro y
		   deja de leerse como el color de la app. */
		--accent: #DC4744;
		--accent-text: #F0837F;
		--accent-soft: rgba(220, 71, 68, 0.18);
		--tint: rgba(242, 239, 232, 0.06);
		--shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 28px -10px rgba(0, 0, 0, 0.7);
		--ring: 0 0 0 4px rgba(220, 71, 68, 0.3);
		--ok: #4FB07C;
		--warn: #D2A24A;
		--bad: #E2685C;
	}
}

/* La escala de toda la app. iOS usa 17px para el texto de un mensaje o de una fila de
   ajustes, y con los 16px por defecto del navegador la app entera se veía un punto más
   pequeña que cualquier app del móvil — esa sensación de "letra chica" que no está en
   ningún sitio concreto sino en todos a la vez.
   Se cambia la RAÍZ y no cada texto: como todo está en rem, sube todo a la vez y las
   proporciones se mantienen. */
html { font-size: 17px; }

body { font-size: 1rem; line-height: 1.6; background-color: var(--bg); }

/* El trazo de la letra. Inter en 400 sale más fina que la tipografía del sistema en un
   iPhone, y al lado de WhatsApp la app entera parecía descolorida — no más pequeña, más
   floja. Se sube el peso base a 500 y se apaga el suavizado "antialiased", que en iOS
   ADELGAZA el texto todavía más. Las dos cosas juntas dan el trazo que se espera.
   Va en body y en los elementos de formulario, que no heredan la tipografía por su cuenta. */
body, input, textarea, select, button {
	font-weight: 500;
	-webkit-font-smoothing: auto;
	-moz-osx-font-smoothing: auto;
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; color: var(--text); }
h1 { font-size: clamp(2.4rem, 5.4vw, 4.2rem); line-height: 1.03; font-weight: 700; }
h2 { font-size: clamp(1.8rem, 3.6vw, 2.6rem); line-height: 1.1; }
h3 { font-size: 1.2rem; line-height: 1.25; font-weight: 600; letter-spacing: -0.01em; }

h1 em, h2 em { font-style: normal; color: var(--accent); }

.eyebrow {
	font-size: 0.72rem; font-weight: 600; text-transform: uppercase;
	letter-spacing: 0.14em; color: var(--accent-text);
}
.lead { font-size: 1.08rem; color: var(--muted); max-width: 34rem; }

.button {
	font-family: var(--font); font-size: 0.88rem; font-weight: 600; letter-spacing: 0;
	text-transform: none; padding: 0.75rem 1.35rem; border-radius: var(--radius-control);
}
.button--light { background: var(--surface); border-color: var(--line); color: var(--text); box-shadow: var(--shadow); }
.button--light:hover { border-color: var(--accent); color: var(--accent-text); }
.button--ghost { background: transparent; border-color: transparent; color: var(--muted); }
.button--ghost:hover { color: var(--accent-text); background: var(--tint); }

/* Cabecera --------------------------------------------------------------------------- */

.topbar {
	position: sticky; top: 0; z-index: var(--z-sticky);
	background: rgba(250, 249, 246, 0.82);
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
	border-bottom: 1px solid var(--line);
}
.topbar-inner { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding-block: 1.05rem; }
/* La marca lleva el CORAZÓN DEL ICONO delante, así que el enlace es una fila: sin esto el
 * dibujo se alinea con la base del texto y queda hundido.
 *
 * Va aquí y no en portada.css porque la cabecera sale en TODAS las páginas —registro,
 * privacidad, términos— y portada.css solo lo carga la portada: el icono aparecería sin
 * medida en todas las demás, que para un SVG significa enorme. */
.brand { font-family: var(--font-display); font-size: 1.35rem; letter-spacing: -0.01em; text-decoration: none; color: var(--text); display: inline-flex; align-items: center; gap: 0.42rem; }
/* En em y no en píxeles: la marca cambia de tamaño entre la cabecera y el pie, y el icono
 * tiene que seguirla sin que nadie se acuerde de ajustarlo. */
.brand-icono { width: 1.05em; height: 1.05em; flex: none; border-radius: 28%; }
.nav { display: flex; align-items: center; gap: clamp(0.9rem, 2.2vw, 1.8rem); }
.nav a { font-size: 0.86rem; font-weight: 500; text-transform: none; letter-spacing: 0; text-decoration: none; color: var(--muted); }
.nav a:hover { color: var(--text); }
.nav a.button { padding: 0.55rem 1.15rem; color: var(--accent-contrast); }
.nav a.button:hover { color: var(--accent-contrast); }
.nav .avatar { border-color: var(--line); background: var(--tint); color: var(--text); }

/* Portada: foto a sangre con velo suave, texto claro encima ------------------------- */

.hero { position: relative; display: grid; align-items: end; min-height: min(84vh, 46rem); overflow: hidden; isolation: isolate; }
.hero-bg { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; }
.hero::after {
	content: ""; position: absolute; inset: 0; z-index: -1;
	background:
		linear-gradient(to top, rgba(12, 10, 6, 0.92) 0%, rgba(12, 10, 6, 0.55) 42%, rgba(12, 10, 6, 0.08) 78%),
		linear-gradient(to right, rgba(12, 10, 6, 0.35), transparent 55%);
}
.hero-inner { position: relative; width: 100%; }
.hero-copy { padding-block: clamp(4rem, 11vw, 8rem) 0; max-width: 42rem; }
.hero-copy h1, .hero-copy .eyebrow { color: #FFFFFF; }
.hero-copy h1 em { color: #F3C2AA; }
.hero-copy .lead { color: rgba(255, 255, 255, 0.82); }
.hero .actions { margin-top: 2rem; }

.figures { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; margin-top: clamp(2rem, 5vw, 3.6rem); padding-block: 1.4rem 2rem; border-top: 1px solid rgba(255, 255, 255, 0.18); }
.figure { display: grid; gap: 0.15rem; }
.figure-num { font-family: var(--font-display); font-size: clamp(1.5rem, 2.8vw, 2.1rem); line-height: 1; color: #FFFFFF; }
.figure-label { font-size: 0.68rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.14em; color: rgba(255, 255, 255, 0.7); }

/* Bandas ---------------------------------------------------------------------------- */

.band { padding-block: clamp(3rem, 6.5vw, 5.5rem); border-top: 1px solid var(--line); scroll-margin-top: 4.5rem; }
.band--tint { background: #F5F1EA; }
.band-head { max-width: 40rem; margin-bottom: clamp(1.8rem, 3.6vw, 2.8rem); }
.band-head p { color: var(--muted); }
.band-head .eyebrow { margin-bottom: 0.8rem; }

/* Quiénes somos ----------------------------------------------------------------------- */

.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.split img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--radius); }
.split .eyebrow { display: block; margin-bottom: 0.8rem; }
.split p { color: var(--muted); }
.facts { display: grid; grid-template-columns: 1fr 1fr; gap: 1.3rem 2rem; margin-top: 2rem; padding-top: 1.6rem; border-top: 1px solid var(--line); }
.fact { display: grid; gap: 0.25rem; }
.fact-label { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.12em; color: var(--accent-text); }
.fact-value { font-family: var(--font-display); font-size: 1.15rem; color: var(--text); }

/* Qué se puede hacer ------------------------------------------------------------------ */

.cards { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(16.5rem, 1fr)); }
.pcard {
	position: relative; display: flex; flex-direction: column; overflow: hidden;
	border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
	color: inherit; text-decoration: none; box-shadow: var(--shadow);
	transition: border-color 0.2s ease, transform 0.2s ease;
}
.pcard:hover { border-color: var(--accent); transform: translateY(-2px); }
.pcard img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.pcard-tag {
	position: absolute; top: 0.9rem; left: 0.9rem; padding: 0.3rem 0.65rem; border-radius: 999px;
	background: rgba(255, 255, 255, 0.92); font-size: 0.68rem; font-weight: 700; text-transform: uppercase;
	letter-spacing: 0.1em; color: var(--accent-text);
}
.pcard-body { display: grid; gap: 0.45rem; padding: 1.3rem 1.4rem 1.5rem; }
.pcard-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.pcard-head h3 { margin: 0; }
.pcard-text { color: var(--muted); font-size: 0.92rem; }

/* Momentos juntos ---------------------------------------------------------------------- */

.mosaic { display: grid; gap: 0.9rem; grid-template-columns: 1.15fr 1fr; }
.shot { position: relative; margin: 0; overflow: hidden; border-radius: var(--radius); }
.shot--wide { grid-row: span 2; }
.shot img { display: block; width: 100%; height: 100%; aspect-ratio: 3 / 2; object-fit: cover; transition: transform 0.6s ease; }
.shot--wide img { aspect-ratio: auto; }
.shot:hover img { transform: scale(1.03); }
.shot figcaption {
	position: absolute; inset: auto 0 0; padding: 2.2rem 1.1rem 1rem;
	background: linear-gradient(to top, rgba(12, 10, 6, 0.85), transparent);
	font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; color: #FFF;
	opacity: 0; transition: opacity 0.25s ease;
}
.shot:hover figcaption { opacity: 1; }

/* Tarjetas sueltas ------------------------------------------------------------------- */

.visit { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.visit .card { background: var(--surface); border-color: var(--line); box-shadow: var(--shadow); }
.visit .card h3 { margin-bottom: 0.9rem; }
.visit-line { margin: 0 0 0.5rem; color: var(--muted); }
.visit-line a { color: var(--accent-text); text-decoration: none; }

/* La banda de cierre -------------------------------------------------------------------- */

.cta { text-align: center; padding-block: clamp(1.2rem, 3vw, 2.4rem); }
.cta h2 { max-width: 24rem; margin-inline: auto; }
.cta p { color: var(--muted); max-width: 30rem; margin-inline: auto; }
.cta .actions { justify-content: center; }

/* Preguntas frecuentes ------------------------------------------------------------------ */

.faq { display: grid; gap: 2.2rem 3rem; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.faq-item h3 { margin: 0 0 0.45rem; font-size: 1.05rem; }
.faq-item p { margin: 0; color: var(--muted); }

/* Pie ------------------------------------------------------------------------------------ */

.foot { border-top: 1px solid var(--line); font-size: 0.82rem; color: var(--muted); }
.foot-top { display: grid; justify-items: center; gap: 1.4rem; padding-block: 2.2rem 1.4rem; }
.foot-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.2rem; }
.foot-nav a { padding: 0.35rem 0.75rem; border-radius: 999px; text-decoration: none; color: var(--muted); font-size: 0.82rem; }
.foot-nav a:hover { color: var(--text); background: var(--tint); }
.foot-bottom { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 0.7rem 2rem; padding-block: 1.4rem 1.8rem; border-top: 1px solid var(--line); }
.foot-contact, .foot-legal { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 1.2rem; }
.foot a { color: var(--text); text-decoration: none; }
.foot a:hover { color: var(--accent-text); }

@media (max-width: 56rem) {
	.split { grid-template-columns: 1fr; }
	.split img { aspect-ratio: 3 / 2; }
	.figures { grid-template-columns: 1fr 1fr; gap: 1.1rem; }
	.mosaic { grid-template-columns: 1fr; }
	.shot--wide { grid-row: auto; }
	.shot--wide img { aspect-ratio: 3 / 2; }
	.nav a:not(.button):not(.account-link) { display: none; }
	.nav--end .account-link { display: inline; }
}

/* Barra inferior tipo app -------------------------------------------------------------- */

/* Las pantallas de la app no son un documento que se lee: el "tirar para recargar" del
   navegador aparecía por debajo de nuestros propios gestos. Aquí el gesto vertical es
   nuestro. */
html:has(body.has-bottomnav), body.has-bottomnav { overscroll-behavior-y: none; }
/* Y el DOCUMENTO no se desplaza. Sin esto, al abrir el teclado iOS desplazaba el documento
   (scrollY llegó a 377 medido en un iPhone) ADEMÁS de correr la ventana visible: dos
   desplazamientos distintos sumándose, y compensando solo uno la cabecera se quedaba
   cortada por arriba. El body ya llevaba overflow hidden; le faltaba al html. */
html:has(body.has-bottomnav) { height: 100%; overflow: hidden; }

/* La app ocupa la pantalla y lo que se desplaza es SU CONTENIDO, no el documento. La barra
   de abajo deja de estar fija al viewport y pasa a ser la última fila de esa columna.
   Es la única forma de que no se despegue: mientras estaba fija, iOS la movía por su cuenta
   al rebotar el scroll o al plegarse la barra del navegador. Un elemento que no está fijo no
   se puede despegar.
   ALTO 100%, NO 100dvh. Parecía lo mismo y no lo es: medido en el iPhone con el teclado
   abierto, `innerHeight` valía 377 y <main> seguía valiendo 637 — el `dvh` NO se entera del
   teclado, así que el body seguía midiendo la pantalla entera dentro de una ventana que ya
   era la mitad. Eso es lo que dejaba el documento desbordado, lo que hacía que iOS lo
   desplazara (scrollY 377), lo que cortaba la cabecera por arriba y lo que hacía saltar el
   hilo al bajar el teclado. El porcentaje se resuelve contra la ventana de DISEÑO, que es
   justo lo que `interactive-widget=resizes-content` encoge: con él, todo —cabecera, hilo,
   compositor y barra— cabe en lo que se ve y no hay nada que compensar. */
body.has-bottomnav {
	height: 100%; display: flex; flex-direction: column; overflow: hidden;
}
body.has-bottomnav > main {
	flex: 1 1 auto; min-width: 0; min-height: 0; overflow-y: auto; overflow-x: hidden;
	overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}
/* El pie de la web pública (marca y enlaces de la landing) no pinta nada en una pantalla de
   app, y al no flotar ya la barra quedaría DEBAJO de ella. Sin ">" a propósito: el pie no
   siempre es hijo directo del body, y con el selector estricto no se ocultaba nada.
   En la web pública, que no lleva barra inferior, sigue igual. */
/* El pie de la web pública no pinta nada en una pantalla de app, y al no flotar ya la barra
   quedaría DEBAJO de ella. Se ataca por tres vías porque una parte del pie la añade la
   PLATAFORMA, fuera de nuestro código, y no sabemos con qué etiqueta llega:
   por clase, por etiqueta, y por posición — todo hermano de la barra que vaya detrás.
   El :not() deja fuera lo nuestro que también va ahí: visores, hojas, barras de reacción y
   la ficha de "vosotros dos".
   **CUIDADO: esta regla es una trampa para cualquier cosa nueva que se escriba después de
   la barra.** La ficha de los dos estuvo días sin abrirse —tocabas las dos caras y no
   pasaba nada— porque su `hidden = false` no puede contra un `display: none` puesto aquí, y
   nada lo decía: ni un error, ni un hueco, ni una consola. Lo que se añada ahí abajo y sea
   flotante se añade también a esta lista, o no existirá.
   En la web pública, que no lleva barra inferior, no aplica ninguna. */
body.has-bottomnav .foot,
body.has-bottomnav footer,
body.has-bottomnav .bottomnav ~ *:not(.visor):not(.sheet-overlay):not(.barra-flotante):not(.losdos-panel):not(script) {
	display: none;
}

.bottomnav {
	flex: 0 0 auto; position: relative; z-index: var(--z-nav);
	display: flex; align-items: flex-start; justify-content: space-around;
	background: rgba(255, 255, 255, 0.92);
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
	border-top: 1px solid var(--line); box-shadow: 0 -4px 20px rgba(24, 22, 15, 0.05);
	padding: 0.55rem 0.25rem calc(0.55rem + env(safe-area-inset-bottom));
}
.bottomnav-item {
	display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
	flex: 1; min-width: 0; padding-block: 0.2rem;
	text-decoration: none; color: var(--muted);
	/* Con seis secciones y la raíz a 17px, las etiquetas se aprietan un poco más para que
	   "Calendario" siga cabiendo en una línea: una etiqueta partida descuadra la altura de
	   toda la barra. */
	font-size: 0.55rem; font-weight: 600; letter-spacing: 0;
	white-space: nowrap;
}
.bottomnav-item svg { width: 1.35rem; height: 1.35rem; stroke-width: 1.7; }
.bottomnav-item:hover { color: var(--accent-text); }
.bottomnav-item.is-active { color: var(--accent-text); }
.bottomnav-item.is-active svg { stroke-width: 2.1; }
.bottomnav-icon {
	display: flex; align-items: center; justify-content: center;
	width: 2.15rem; height: 2.15rem; border-radius: 50%;
	background: var(--accent); flex-shrink: 0;
	transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.bottomnav-icon svg { width: 1.15rem; height: 1.15rem; stroke: var(--accent-contrast); }
.bottomnav-item:hover .bottomnav-icon { box-shadow: 0 4px 12px rgba(197, 44, 43, 0.3); }
.bottomnav-item.is-active .bottomnav-icon { box-shadow: 0 0 0 3px var(--accent-soft); }
/* El punto de "tienes mensajes sin leer" sobre el icono del chat. Sobre el icono y no al
   lado del texto: el icono es lo que se mira de reojo al pasar por la barra. Borde del color
   del fondo para que se despegue del círculo del acento, que es del mismo tono. */
.bottomnav-punto {
	position: absolute; top: -0.1rem; right: -0.1rem;
	width: 0.55rem; height: 0.55rem; border-radius: 50%;
	background: var(--bad, #C0392B); border: 2px solid var(--bg, #FAF9F6);
}
.bottomnav-icon { position: relative; }

/* ═══ EN UN ORDENADOR EL MENÚ SE VA A LA IZQUIERDA ═════════════════════════════════════
   Una barra pegada abajo es de un móvil: en una pantalla ancha deja seis iconos perdidos en
   un cinturón de treinta centímetros, y el sitio que sobra está justo donde no se usa —a los
   lados. En el escritorio el menú pasa a ser una columna a la izquierda, que es donde se
   busca en cualquier aplicación de ordenador.

   Es SOLO CSS y el mismo marcado: el partial no cambia, el marcado activo se sigue marcando
   igual, y lo que decide es el ancho de la ventana, no un "si es un PC" adivinado por el
   user-agent — una ventana estrecha en un ordenador sigue mereciendo la barra de abajo.

   El menú va FIJO al viewport y el contenido se aparta con un margen del MISMO ancho, en vez
   de convertir el body en una fila: el body es una columna de la que cuelgan la cabecera, el
   contenido y el compositor del chat, y volverla fila los pondría a los tres en paralelo. */
/* Lo que SOLO cabe en la columna del escritorio: Gastos y Tareas. Abajo, con seis ya
   apretados, un séptimo y un octavo dejan las etiquetas partidas — y una barra de iconos sin
   palabra hay que aprendérsela. Se esconden aquí y el bloque de 900px las enseña. */
.bottomnav-item--ancho { display: none; }

@media (min-width: 900px) {
	body.has-bottomnav { margin-left: var(--ancho-menu); }
	body.has-bottomnav > .bottomnav .bottomnav-item--ancho { display: flex; }
	/* Con "> " a propósito, y no `.bottomnav` a secas: la galería de widgets incluye el
	   partial DE VERDAD dentro de un marco para poder enseñarlo, y ese no es el menú de la
	   pantalla — pegarlo también a la izquierda lo sacaría de su marco. */
	body.has-bottomnav > .bottomnav {
		position: fixed; top: 0; left: 0; bottom: 0; width: var(--ancho-menu);
		flex-direction: column; align-items: stretch; justify-content: flex-start;
		gap: 0.15rem; overflow-y: auto;
		/* El borde y la sombra giran con la barra: siguen separándola del contenido, que
		   ahora está a su derecha y no encima. */
		border-top: none; border-right: 1px solid var(--line);
		box-shadow: 4px 0 20px rgba(24, 22, 15, 0.05);
		padding: 1rem 0.6rem calc(1rem + env(safe-area-inset-bottom));
	}
	body.has-bottomnav > .bottomnav .bottomnav-item {
		/* Sin `flex: 1`: en columna eso repartiría el alto entre los seis y dejaría cada
		   botón con un palmo de aire por dentro. */
		flex: 0 0 auto; flex-direction: row; align-items: center; gap: 0.7rem;
		padding: 0.45rem 0.6rem; border-radius: 999px;
		/* Aquí el ancho no es el problema, así que la etiqueta se lee a su tamaño. */
		font-size: 0.85rem;
	}
	/* Lo activo se señala con la píldora ENTERA, no solo con el color de la letra: en
	   vertical hay sitio de sobra y así se ve de un vistazo dónde estás. */
	body.has-bottomnav > .bottomnav .bottomnav-item:hover,
	body.has-bottomnav > .bottomnav .bottomnav-item.is-active { background: var(--accent-soft); }
	body.has-bottomnav > .bottomnav .bottomnav-icon { width: 2rem; height: 2rem; }
	/* Y el menú NO se aparta al escribir: la regla que lo esconde existe porque en un móvil
	   el teclado lo empujaba contra el campo de escribir, y en un ordenador no hay teclado
	   que tape nada. Lleva las dos clases del body porque la que esconde está MÁS ABAJO en
	   el fichero, y a igualdad de peso gana la última. */
	body.has-bottomnav.escribiendo > .bottomnav { display: flex; }
	/* Lo que cuelga fijo de la esquina IZQUIERDA se corre lo que mide el menú: va pegado al
	   viewport, no al contenido, así que sin esto sale encima de la columna. Lo de la
	   derecha —la campanita, la lupa— no se entera de nada. */
	.losdos-panel { left: calc(var(--ancho-menu) + 0.6rem); }
	/* Y la columna se ensancha un 25%: en un móvil el tope no se alcanza nunca, pero en un
	   ordenador es lo único que decide el ancho de la pantalla, y 34rem en medio de una
	   ventana de 1600 px deja una tira estrecha con dos desiertos a los lados. */
	:root { --ancho-app: 42.5rem; }
}

/* El chat de los dos: burbujas tipo mensajería — las tuyas a la derecha con el acento, las
   suyas a la izquierda con su avatar. Mismo lenguaje que las notas de un plan, para que no
   haya dos maneras distintas de pintar un mensaje en la misma app. */
/* La cabecera de la app: una barra fija arriba, con el título a la izquierda y la campanita
   a la derecha, igual en todas las pantallas. Va FUERA de <main> —que es lo que se
   desplaza— así que no se mueve nunca, ni al bajar por el contenido ni al abrir el teclado.
   Inicio no la lleva a propósito: ahí el protagonista es la pareja, no un título. */
.topbar {
	flex: 0 0 auto; position: relative; z-index: var(--z-nav);
	display: flex; align-items: center; gap: 0.6rem;
	background: var(--bg, #FAF9F6); border-bottom: 1px solid var(--line);
	padding: 0.5rem 0.9rem;
}
/* LA RECARGA DEL LATIDO, FUNDIDA. Cuando tu pareja cambia algo de la pantalla que miras, la
 * página se vuelve a pedir (app.js, `recargarSinPerderElSitio`); con esto el navegador deja
 * la de antes en pantalla hasta que la nueva está lista y pasa de una a otra fundiendo, en
 * vez de un pantallazo en blanco. Solo esa recarga: app.js se salta la transición en todas
 * las demás navegaciones (`pagereveal`). Un navegador sin transiciones recarga como antes. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.18s; }
/* LA CABECERA DE LA WEB PÚBLICA (partials/header.html) también se llama `.topbar`, y la regla
 * de arriba —la de la barra de la app— le quitaba el `sticky` y la volvía una fila flex: el
 * menú se iba con el scroll y, en el móvil, el cajón de la hamburguesa (que site.js cuelga
 * DEBAJO de la fila) quedaba al lado, aplastado e invisible. La de la app es un <div>, así
 * que `header.topbar` es solo la pública y le devuelve lo suyo. */
header.topbar { position: sticky; top: 0; display: block; padding: 0; }
header.topbar .nav a { white-space: nowrap; }
/* En un móvil estrecho no caben marca, "Empieza gratis" e "Iniciar sesión" en una fila:
 * "Iniciar sesión" se esconde de la barra y site.js la pasa al cajón, que es justo lo que
 * hace con todo enlace que la página no enseña. */
@media (max-width: 30rem) { header.topbar .nav a.account-link { display: none; } }
.topbar-titulo {
	font-size: 1.2rem; margin: 0; min-width: 0;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Con una hoja abierta la cabecera se queda, pero DETRÁS del fondo oscurecido: baja de
   capa y se oscurece como todo lo demás, así se intuye que sigue ahí, al fondo. Quitarla
   dejaba un vacío blanco arriba; dejarla por delante la hacía parecer un trozo de otra
   pantalla colado sobre la hoja. */
body.hoja-abierta .topbar { z-index: 0; }
/* Dentro de la barra, la campanita deja de flotar: es un elemento más de la fila, empujado
   a la derecha. Flotando encima se montaba sobre los títulos largos.
   RELATIVE, no static: el punto rojo va en absolute, y con la campanita sin posicionar se
   anclaba a la barra entera y aparecía en la esquina de la pantalla, lejos de la campana y
   sin que se entendiera de qué era. */
.topbar .campanita {
	position: relative; margin-left: auto; flex-shrink: 0;
	/* Y sus coordenadas de cuando flota se anulan: en relative dejan de ignorarse y pasan a
	   DESPLAZARLA dentro de la fila, que es lo que la descuadró del nombre. */
	top: auto; right: auto;
	width: 2.4rem; height: 2.4rem; background: none; border: none; backdrop-filter: none;
}
.chat-cabecera-foto {
	width: 2.2rem; height: 2.2rem; border-radius: 50%; object-fit: cover; flex-shrink: 0;
}
/* LAS DOS CARAS de la cabecera del chat: superpuestas, ocupan lo que una. Esta conversación
   es de los dos, y una sola cara la convierte en "su" chat. Las dos llevan el MISMO aro: con
   aro solo la de delante, una parecía más grande que la otra. */
.topbar-caras {
	display: flex; align-items: center; background: none; border: none; padding: 0;
	cursor: pointer; flex-shrink: 0;
}
.topbar-caras .chat-cabecera-foto { border: 2px solid var(--bg); }
.topbar-caras .chat-cabecera-foto--mia { margin-left: -0.75rem; }

/* VOSOTROS DOS: el popup que cuelga de esas caras. Pegado arriba y no una hoja desde abajo —
   la hoja tapa la conversación y se siente como irse a otro sitio. */
.losdos-panel {
	position: fixed; z-index: 60; top: 3.6rem; left: 0.6rem;
	display: flex; gap: 0.9rem;
	width: min(21rem, calc(100vw - 1.2rem));
	padding: 0.9rem;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	box-shadow: 0 12px 30px rgba(0,0,0,0.16);
}
.losdos-col {
	flex: 1; min-width: 0; display: flex; flex-direction: column;
	align-items: center; gap: 0.25rem; text-align: center;
}
.losdos-col strong { font-size: 0.9rem; }
.losdos-cara img { width: 4rem; height: 4rem; border-radius: 50%; object-fit: cover; }
.losdos-visto { font-size: 0.72rem; color: var(--muted); }
/* Cuánto le queda al estado. Más pequeño y apagado que la frase: es el pie de algo, no una
   segunda cosa que leer — y vacío no ocupa, que un hueco fijo debajo de cada estado dejaría
   la ficha descuadrada cuando no hay ninguno. */
.losdos-caduca { font-size: 0.68rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.losdos-caduca:empty { display: none; }
/* El estado puede ser largo: se deja respirar hasta cuatro líneas y ahí se corta. */
.losdos-estado {
	font-size: 0.8rem; color: var(--text);
	display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
/* El lápiz es un BOTÓN, no un enlace: ya no lleva a ninguna parte — abre el campo aquí
   mismo. Se le quita la cara de botón para que siga leyéndose como el lapicito de antes. */
.losdos-lapiz {
	background: none; border: none; padding: 0; font: inherit; cursor: pointer;
	text-decoration: none; color: var(--accent-text, var(--accent));
}
/* El campo de escribir el estado, dentro de la ficha. En columna y a todo el ancho de su
   mitad: el popup mide unas 21rem y una fila de campo + botón deja el campo en tres
   caracteres. */
.losdos-editar {
	display: grid; gap: 0.35rem; width: 100%;
}
.losdos-editar input {
	width: 100%; box-sizing: border-box;
	font-size: 0.85rem; padding: 0.35rem 0.5rem;
	border: 1px solid var(--line); border-radius: var(--radius-sm);
	background: var(--bg); color: var(--text);
}
.losdos-editar .button { padding: 0.3rem 0.7rem; font-size: 0.8rem; }
.losdos-editar .status { margin: 0; font-size: 0.75rem; }
/* "La última: «...»" — repetir lo que ya pusiste. Es un atajo, no un botón principal: se
   lee como un enlace y no compite con Guardar, que es el que decide. */
.losdos-repetir {
	background: none; border: none; padding: 0; cursor: pointer; text-align: left;
	font: inherit; font-size: 0.75rem; color: var(--accent-text, var(--accent));
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Con la cabecera fuera, el respiro de arriba de la pantalla lo daba el título; ahora ese
   hueco se queda vacío y enorme. Las pantallas de la app arrancan justo debajo de la barra,
   con el mismo margen todas — 0.9rem — para que se vean de la misma familia.
   .band trae 3-5rem porque es un estilo de la web pública, donde cada franja necesita ese
   aire; dentro de la app no. */
body:has(.topbar) main > .band,
body:has(.topbar) main > .wrap { padding-top: 0.9rem; }
body:has(.topbar) main > .band { border-top: none; }
.chat-hilo {
	list-style: none; margin: 0; padding: 0;
	display: flex; flex-direction: column; gap: 0.35rem;
}
/* EL FONDO CON PATRÓN DE TODA LA APP, el mismo que la nativa.
   Una pantalla sobre un color plano se lee como un formulario; el patrón es lo que hace que
   esto parezca un sitio. Va MUY tenue a propósito: lo que se tiene que leer es el contenido,
   y los dibujos son de ESTA app —fotos, planes, café, música— no los garabatos genéricos de
   una mensajería cualquiera.
   Va en `body:has(.topbar)`, que es como se distingue aquí "dentro de la app" de la web
   pública: la portada de la marca tiene su propio diseño y no lo quiere.
   Es un SVG embebido y no un fichero: una imagen habría que servirla, cachearla y llevarla
   en dos versiones; así basta con cambiarle el color en el bloque de noche.
   El CHAT ya no lleva cabecera (sube como una hoja): ahí el patrón va en la hoja, su <main>. */
body:has(.topbar), body.chat-hoja > main {
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='300' viewBox='0 0 300 300'><g fill='%23000000' fill-opacity='0.05' font-family='system-ui,sans-serif' text-anchor='middle'><text x='34' y='38' font-size='19' transform='rotate(-18 34 38)'>&#9829;&#xFE0E;</text><text x='104' y='20' font-size='25' transform='rotate(13 104 20)'>&#9786;&#xFE0E;</text><text x='176' y='52' font-size='17' transform='rotate(-7 176 52)'>&#9834;&#xFE0E;</text><text x='244' y='26' font-size='21' transform='rotate(26 244 26)'>&#9733;&#xFE0E;</text><text x='272' y='96' font-size='23' transform='rotate(-11 272 96)'>&#9788;&#xFE0E;</text><text x='58' y='98' font-size='21' transform='rotate(16 58 98)'>&#9749;&#xFE0E;</text><text x='136' y='116' font-size='25' transform='rotate(-27 136 116)'>&#9992;&#xFE0E;</text><text x='210' y='134' font-size='19' transform='rotate(9 210 134)'>&#10047;&#xFE0E;</text><text x='26' y='156' font-size='23' transform='rotate(-13 26 156)'>&#9729;&#xFE0E;</text><text x='92' y='182' font-size='17' transform='rotate(21 92 182)'>&#10022;&#xFE0E;</text><text x='162' y='200' font-size='21' transform='rotate(-16 162 200)'>&#9790;&#xFE0E;</text><text x='252' y='188' font-size='19' transform='rotate(11 252 188)'>&#9998;&#xFE0E;</text><text x='46' y='244' font-size='23' transform='rotate(15 46 244)'>&#10085;&#xFE0E;</text><text x='118' y='270' font-size='21' transform='rotate(-9 118 270)'>&#9836;&#xFE0E;</text><text x='196' y='256' font-size='15' transform='rotate(19 196 256)'>&#9733;&#xFE0E;</text><text x='266' y='276' font-size='17' transform='rotate(-21 266 276)'>&#9829;&#xFE0E;</text></g></svg>");
	background-repeat: repeat;
}
/* El hueco para el disco de la reacción ya NO se reserva aquí: lo reserva la propia
   burbuja que lo lleva (regla "Y LA ESQUINA ES SUYA", en el bloque de LA REACCIÓN). Aquí
   había un margen a ojo que solo servía para el chat, y otro distinto en la fila de fotos,
   y otro en el calendario. */
/* ═══ LA BURBUJA ════════════════════════════════════════════════════════════════════════
   UNA sola burbuja de mensaje en toda la app: el chat y las entradas de un reto. Los
   nombres .reto-msg-* son ALIAS de estos, para que el marcado que ya existe se lleve cada
   arreglo sin tocarlo — el mismo trato que los nombres viejos del disco de la reacción. */
.chat-fila, .reto-msg-fila { display: flex; align-items: flex-end; gap: 0.4rem; }
.chat-fila--mia, .reto-msg-fila--mia { justify-content: flex-end; }
.chat-burbuja, .reto-msg-burbuja {
	max-width: 78%; padding: 0.5rem 0.7rem 0.35rem; border-radius: 1rem;
	background: var(--surface); border: 1px solid var(--line);
	/* 1rem clavado, como el texto de un mensaje en cualquier app de mensajería: aquí el
	   texto ES el contenido, no un pie de foto ni una etiqueta. */
	font-size: 1rem; line-height: 1.4; word-break: break-word;
}
/* Los saltos de línea de un mensaje los conserva SU TEXTO, no la burbuja. Con el pre-wrap
   en la burbuja entera, cualquier salto del MARCADO —una plantilla escrita en varias
   líneas, como las muestras de la galería— se pintaba como línea en blanco: la misma
   burbuja salía normal en el chat (que la construye desde código, sin espacios) y de tres
   dedos de alto en la galería. Una pieza que se ve distinta según quién la escriba no está
   encapsulada. Aquí dentro, y solo aquí, los saltos son del mensaje. */
.chat-burbuja-texto { white-space: pre-wrap; }
.chat-burbuja--mia, .reto-msg-burbuja--mia { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
/* Un mensaje pintado pero todavía sin confirmar: se ve que está en camino, sin ponerle un
   reloj ni un icono que habría que explicar. Vuelve a su color en cuanto el servidor
   contesta, que es casi siempre al instante. */
.chat-burbuja--enviando { opacity: 0.55; }
/* La hora, dentro de la burbuja y en su propia línea a la derecha: fuera obligaría a
   reservar una franja para algo que casi nadie mira. */
.chat-hora {
	display: block; text-align: right; font-size: 0.62rem; margin-top: 0.15rem;
	/* Se atenúa por COLOR y no por opacity: la opacity se hereda y apagaba también el
	   disco del tic de leído, que va dentro de esta línea y tiene que verse a tope. */
	color: color-mix(in srgb, currentColor 65%, transparent);
}
.chat-dia {
	align-self: center; margin: 0.6rem 0 0.2rem;
	font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em;
}
/* El campo de escribir, pegado encima de la barra de navegación: en un chat es lo primero
   que se busca al entrar. Fuera de <main> para que no se desplace con los mensajes. */
.chat-pie {
	flex: 0 0 auto; position: relative; z-index: var(--z-nav);
	background: var(--bg, #FAF9F6); border-top: 1px solid var(--line);
	padding: 0.5rem 0.9rem;
}
/* Un aviso vacío no ocupa sitio. Un <p> sin texto sigue reservando su línea y su margen, y
   eso es un hueco muerto justo debajo de cada campo de escribir — se vio en el chat y otra
   vez en el coach. Se arregla para TODOS los avisos de la app, no de uno en uno. */
.status:empty { display: none; }
.chat-pie .status { margin: 0.4rem 0 0 !important; }
/* "Está escribiendo", al final del hilo. Los tres puntos van desfasados entre sí: es lo que
   hace que se lea como alguien tecleando y no como una barra de carga. */
.chat-escribiendo-aviso {
	display: flex; align-items: center; gap: 0.4rem;
	margin: 0.4rem 0 0; font-size: 0.8rem; color: var(--muted);
}
.chat-puntos { display: inline-flex; gap: 0.15rem; }
.chat-puntos i {
	width: 0.32rem; height: 0.32rem; border-radius: 50%; background: currentColor;
	animation: chat-punto 1.2s ease-in-out infinite;
}
.chat-puntos i:nth-child(2) { animation-delay: 0.2s; }
.chat-puntos i:nth-child(3) { animation-delay: 0.4s; }
@keyframes chat-punto { 0%, 60%, 100% { opacity: 0.25; } 30% { opacity: 1; } }
.chat-pie .enviar-inline { width: 100%; }
/* El compositor es una fila: botones a los lados, campo en medio. .enviar-inline solo sabe
   de "un campo con su icono dentro", así que envuelve al campo y no al formulario entero —
   metiendo los botones ahí dentro se colocaban ENCIMA del campo, cada uno en su línea. */
.chat-compositor { display: flex; align-items: center; gap: 0.35rem; }
.chat-campo { flex: 1; min-width: 0; display: block; }
/* Mientras se graba, el compositor se va entero y esta fila ocupa su sitio: no se puede
   escribir y grabar a la vez, y dejar el campo ahí solo invita a intentarlo. */
/* Grabando una nota de voz: a PANTALLA COMPLETA, como el vídeo. Mientras grabas no hay nada
   más que hacer, y en una franja de un dedo dentro del compositor no se veía ni el tiempo. */
.chat-grabando {
	position: fixed; inset: 0; z-index: var(--z-visor, 90);
	background: #000; display: flex; flex-direction: column;
	align-items: center; justify-content: center; gap: 1rem; padding: 0;
}
/* La onda: cinco barras que suben y bajan a destiempo. No mide la voz de verdad —eso pediría
   analizar el micro— pero dice lo único que hace falta: esto está grabando. */
.chat-onda { display: flex; align-items: center; gap: 0.35rem; height: 4rem; }
.chat-onda i {
	display: block; width: 0.5rem; height: 100%; border-radius: 999px;
	background: var(--accent); transform-origin: center;
	animation: onda 0.9s ease-in-out infinite;
}
.chat-onda i:nth-child(2) { animation-delay: 0.15s; }
.chat-onda i:nth-child(3) { animation-delay: 0.3s; }
.chat-onda i:nth-child(4) { animation-delay: 0.45s; }
.chat-onda i:nth-child(5) { animation-delay: 0.6s; }
@keyframes onda { 0%, 100% { transform: scaleY(0.25); } 50% { transform: scaleY(1); } }
.chat-grabando-tiempo {
	color: #FFFFFF; font-size: 2rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.chat-grabando-texto { color: rgba(255, 255, 255, 0.7); font-size: 0.95rem; }
.chat-grabando-botones { display: flex; gap: 0.8rem; margin-top: 0.4rem; }
/* El <audio> del sistema NO se ve: es solo el motor que suena. Todo lo que se ve —el botón
   redondo, la barra blanca, el tiempo— lo pintamos nosotros más abajo. Aquí había una regla
   que lo mostraba a su tamaño nativo, y como iba antes en el fichero seguía saliendo el
   control feo por debajo del nuestro. */
.chat-audio { display: none !important; }
/* ---- Nota de voz: reproductor PROPIO -------------------------------------------------
   El <audio> de arriba no se ve: es solo el motor que suena —y el que sabe pausar al entrar
   una llamada y salir en la pantalla de bloqueo—. Todo lo demás se pinta aquí, que es lo
   único que permite un play a tamaño de dedo y una onda en vez de una barra corriente. */
.chat-audio-fila { display: flex; align-items: center; gap: 0.55rem; min-width: 12.5rem; }
.chat-burbuja .chat-audio-fila { margin: -0.15rem 0; }
.chat-audio-play {
	flex: 0 0 auto; width: 2.9rem; height: 2.9rem; border-radius: 50%;
	border: none; cursor: pointer; padding: 0;
	display: flex; align-items: center; justify-content: center;
	background: rgba(255, 255, 255, 0.25); color: #FFFFFF;
}
.chat-fila:not(.chat-fila--mia) .chat-audio-play { background: var(--accent); color: #FFFFFF; }
/* La ONDA: palitos de alturas distintas. Los ya oídos en blanco pleno, los que faltan
   translúcidos. Es lo que hace que una nota de voz se reconozca como voz de un vistazo. */
.chat-audio-onda {
	flex: 1; min-width: 5rem; height: 1.8rem; cursor: pointer;
	display: flex; align-items: center; gap: 2px;
}
.chat-audio-onda i {
	flex: 1; min-width: 2px; border-radius: 999px;
	background: rgba(255, 255, 255, 0.35); transition: background 0.15s linear;
}
.chat-audio-onda i.is-oido { background: #FFFFFF; }
.chat-fila:not(.chat-fila--mia) .chat-audio-onda i { background: rgba(127, 127, 127, 0.3); }
.chat-fila:not(.chat-fila--mia) .chat-audio-onda i.is-oido { background: var(--accent); }
.chat-audio-tiempo {
	flex: 0 0 auto; font-size: 0.72rem; font-variant-numeric: tabular-nums; opacity: 0.85;
}
.chat-audio-vel {
	flex: 0 0 auto; background: rgba(127, 127, 127, 0.25); border: none; color: inherit;
	font: inherit; font-size: 0.7rem; font-weight: 700;
	padding: 0.2rem 0.4rem; border-radius: 999px; cursor: pointer;
}
/* La rueda ocupa el hueco del icono DENTRO del botón: el sitio donde miras es el mismo antes,
   durante y después. */
.chat-audio-fila.is-cargando .chat-audio-play > svg { display: none; }
.chat-audio-fila.is-cargando .chat-audio-play::after {
	content: ""; width: 1.2rem; height: 1.2rem;
	border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
	animation: girar 0.8s linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }
/* UN BOTÓN OCUPADO: el que acabas de tocar para mandar algo, mientras eso se manda. Se
   apaga al dedo y enseña una rueda EN SU SITIO —no un texto en otra parte— porque es ahí
   donde estás mirando, y porque el segundo toque nervioso que mandaba la foto dos veces
   caía justo ahí. El ancho se conserva: un botón que se encoge al pulsarlo parece roto. */
.is-ocupado {
	pointer-events: none; position: relative; color: transparent !important;
}
.is-ocupado::after {
	content: ""; position: absolute; top: 50%; left: 50%;
	width: 1.1rem; height: 1.1rem; margin: -0.55rem 0 0 -0.55rem;
	border: 2px solid rgba(255, 255, 255, 0.9); border-top-color: transparent;
	border-radius: 50%; animation: girar 0.8s linear infinite;
}
.is-ocupado.button--light::after, .is-ocupado.chat-accion::after { border-color: currentColor; border-top-color: transparent; color: var(--text); }
/* Una nota YA ESCUCHADA se apaga entera —onda y botón— y lo dice con un tic, no con una
   palabra: el texto pedía sitio en una fila que ya lleva tiempo y velocidad, y un tic se
   entiende igual en las dos direcciones. En TU burbuja significa que tu pareja la escuchó. */
.chat-burbuja--oida .chat-audio-play,
.chat-burbuja--oida .chat-audio-onda { opacity: 0.5; }
.chat-burbuja--oida .chat-audio-tiempo::after {
	content: " ✓"; font-weight: 700; opacity: 0.95;
}
.chat-audio-duracion { display: block; font-size: 0.7rem; opacity: 0.7; margin-top: 0.15rem; }
/* DIAGNÓSTICO TEMPORAL del teclado (?debug=1). Se quita en cuanto esté resuelto. */
.chat-debug {
	margin: 0.4rem 0 0; padding: 0.5rem 0.7rem; border-radius: 0.5rem;
	background: #111; color: #7CFF9B; font-size: 0.72rem; line-height: 1.35;
	white-space: pre; overflow-x: auto;
}
/* Un sticker se pinta SIN burbuja: una pegatina con un marco de color alrededor deja de
   parecer una pegatina. Y más grande que una foto, que es todo el chiste. */
.chat-burbuja--sticker {
	background: none !important; border: none !important; padding: 0 !important;
	max-width: 44%;
}
.chat-burbuja--sticker .chat-hora { color: var(--muted); opacity: 1; }
.chat-sticker { display: block; width: 8.5rem; max-width: 100%; }
/* Deslizar un mensaje hacia el centro lo cita. El gesto horizontal es NUESTRO —touch-action
   pan-y deja al navegador solo el desplazamiento vertical—, o iOS se lleva el dedo a mitad
   de camino y el gesto muere sin terminar. Mientras se arrastra, la burbuja se mueve con el
   dedo (el transform lo pone el JS) y al pasar el umbral se enciende para que se vea que ya
   vale con soltar. */
.chat-burbuja { touch-action: pan-y; }
.chat-burbuja--responder { box-shadow: 0 0 0 2px var(--accent); }
/* El mensaje al que lleva una cita, señalado un segundo al llegar. */
.chat-burbuja--senalada { box-shadow: 0 0 0 2px var(--accent); transition: box-shadow 0.2s ease; }
/* LA BARRA DE SALDO DEL COACH: cuánto queda, sin decir de qué.
   Es un depósito, no una cuenta: quien lo mira quiere saber si le llega para seguir, no
   cuántas unidades le quedan de algo que no sabe lo que vale. Por eso no lleva número. */
.saldo-barra {
	display: inline-block; width: 4.5rem; height: 0.5rem;
	background: var(--line); border-radius: 999px; overflow: hidden;
	vertical-align: middle;
}
.saldo-barra-lleno {
	display: block; height: 100%; background: var(--accent);
	border-radius: 999px; transition: width 0.3s ease;
}

/* EL CAMPO DE LA TARJETA.
/* EL CAMPO DE LA TARJETA. Por dentro es un iframe de la pasarela —el número no está nunca en
   un documento nuestro—, así que aquí solo se dibuja la caja que lo rodea, y se dibuja igual
   que los demás campos del formulario para que no parezca pegado de otra web. */
.cardfield {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: 0.6rem; padding: 0.85rem 0.9rem;
}
.cardfield.is-focus { border-color: var(--accent); }

/* DE DÓNDE VINO: un mensaje que se trajo del álbum, de los agradecimientos o de un plan.
   Va arriba del todo de la burbuja, en versalitas y apagado — es una etiqueta de origen, no
   parte de lo que se dijo, y con el mismo cuerpo del texto se leería como una frase más. */
.chat-origen {
	display: block; font-size: 0.66rem; font-weight: 700;
	text-transform: uppercase; letter-spacing: 0.03em;
	opacity: 0.75; margin-bottom: 0.2rem;
}
/* En un mensaje de tu pareja el fondo es claro: ahí la etiqueta va del color apagado, que es
   el que se lee sobre claro sin competir con el texto. */
.chat-fila:not(.chat-fila--mia) .chat-origen { color: var(--muted); opacity: 1; }
/* La cita dentro de la burbuja: una línea con quién lo dijo y qué decía, con la barra de
   color a la izquierda que se lee como "esto es de más arriba" en cualquier mensajería. */
.chat-cita {
	/* En rejilla y pegada arriba: el nombre y la línea citada, uno debajo del otro y sin más
	   hueco que el que se pide aquí. Como bloque suelto, el espacio entre los dos dependía de
	   lo que heredara de la burbuja —interlineado incluido— y se abría un vacío que no había
	   puesto nadie. */
	display: grid; gap: 0.1rem; align-content: start;
	width: 100%; text-align: left; cursor: pointer;
	background: rgba(255, 255, 255, 0.16); border: none;
	border-left: 3px solid rgba(255, 255, 255, 0.65);
	border-radius: 0.45rem; padding: 0.35rem 0.5rem; margin-bottom: 0.3rem;
	font: inherit; color: inherit; line-height: 1.25;
}
/* En un mensaje de tu pareja el fondo es claro, así que la cita se tiñe del acento. */
.chat-fila:not(.chat-fila--mia) .chat-cita {
	background: var(--tint); border-left-color: var(--accent);
}
/* El nombre de quien lo dijo: UNA línea, pase lo que pase. El texto citado puede venir de
   cualquier sitio —del <h1> de la cabecera, por ejemplo, que trae los saltos del HTML— y un
   nombre no tiene saltos: aquí se dice, y así no depende de que quien lo lea se acuerde de
   limpiarlo. */
.chat-cita-quien {
	display: block; font-size: 0.72rem; font-weight: 700; opacity: 0.9;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-cita-texto {
	display: block; font-size: 0.78rem; opacity: 0.85;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* La cita del compositor: lo mismo, encima del campo, hasta que mandas o la quitas. */
.chat-respondiendo {
	display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.4rem;
	background: var(--tint); border-left: 3px solid var(--accent);
	border-radius: 0.45rem; padding: 0.35rem 0.5rem;
}
.chat-respondiendo-texto {
	flex: 1; min-width: 0; font-size: 0.8rem; color: var(--muted);
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Los chips del filtro de avisos: una fila que se desplaza a lo ancho si no cabe, en vez de
   partirse en dos líneas y comerse media pantalla antes del primer aviso. */
.avisos-filtros {
	display: flex; gap: 0.35rem; margin-top: 0.6rem;
	overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 0.2rem;
	scrollbar-width: none;
}
.avisos-filtros::-webkit-scrollbar { display: none; }
.avisos-filtros .chip { flex: 0 0 auto; text-decoration: none; }

/* Una encuesta dentro de una burbuja: la pregunta y sus opciones como botones. Con dos
   personas, lo que importa no es cuántos votos hay sino QUIÉN votó qué — de ahí las caras
   en vez de un contador. */
.chat-encuesta { display: grid; gap: 0.3rem; min-width: 12rem; }
.chat-encuesta-pregunta { font-weight: 700; font-size: 0.95rem; margin-bottom: 0.15rem; }
/* Las opciones, SIEMPRE sobre fondo claro y texto oscuro, aunque la burbuja sea del acento:
   son botones que hay que leer y tocar, y un gris translúcido encima del terracota
   desaparecía. Es también lo que hace que se lean igual en tu burbuja y en la suya. */
.chat-encuesta-opcion {
	display: flex; align-items: center; gap: 0.4rem; width: 100%; box-sizing: border-box;
	background: var(--surface); color: var(--text);
	/* El borde mide SIEMPRE lo mismo y solo cambia de color. Antes la votada sumaba un aro
	   interior encima del borde: la caja medía igual, pero el trazo doble la hacía parecer
	   más ancha que su vecina — y dos botones de la misma lista tienen que verse iguales. */
	border: 2px solid transparent;
	border-radius: 0.6rem; padding: 0.45rem 0.6rem;
	font: inherit; font-size: 0.88rem; cursor: pointer; text-align: left;
}
/* En la burbuja de tu pareja el fondo YA es esa superficie, así que la opción se separa con
   el tinte: sin esto sería un botón blanco sobre blanco. */
.chat-fila:not(.chat-fila--mia) .chat-encuesta-opcion { background: var(--tint); }
/* La votada, con el filo del acento y algo más de peso. Mismo grosor, otro color. */
.chat-encuesta-opcion.is-votada { border-color: var(--accent); font-weight: 600; }
.chat-encuesta-caras { margin-left: auto; display: flex; }
.chat-encuesta-caras .reto-avatar-mini { width: 1.15rem; height: 1.15rem; }
.chat-encuesta-caras > * + * { margin-left: -0.35rem; }

/* Un mensaje que es SOLO emojis: grande y sin burbuja, como en cualquier mensajería. Un
   corazón del tamaño de una letra no dice lo que quiere decir.
   Sin BORDE tampoco: quitar el fondo y la sombra y dejar el borde deja un recuadro vacío
   alrededor del emoji, que es peor que la burbuja entera — se ve un marco y no se sabe de
   qué. Y grande de verdad (4,4rem): a 3,2 seguía pareciendo texto.
   La hora se queda pequeña y de su color: es información, no parte del gesto. */
.chat-burbuja--emoji {
	background: none !important; box-shadow: none !important; border: none !important;
	padding: 0 0.2rem !important;
	font-size: 4.4rem; line-height: 1.1;
}
.chat-burbuja--emoji .chat-hora { font-size: 0.7rem; }
.chat-fila--mia .chat-burbuja--emoji .chat-hora { color: var(--muted); }

/* ---- Editor de stickers ---------------------------------------------------------------
   El lienzo: la imagen y, encima, las capas de texto y emojis que se arrastran. */
.sticker-lienzo {
	position: relative; width: 100%; max-width: 22rem; aspect-ratio: 1;
	justify-self: center; border-radius: var(--radius-sm); overflow: hidden;
	background: var(--tint); touch-action: none;
}
.sticker-lienzo > img { width: 100%; height: 100%; object-fit: contain; display: block; }
.sticker-capa {
	position: absolute; transform: translate(-50%, -50%);
	white-space: nowrap; line-height: 1; cursor: move; touch-action: none;
	padding: 0.1rem 0.2rem;
}
.sticker-capa-txt { outline: none; }
/* El texto, blanco con borde negro: es lo único que se lee sobre cualquier imagen, clara u
   oscura, y por eso lo usa todo el mundo desde hace veinte años. */
.sticker-capa--texto {
	color: #FFFFFF; font-weight: 800;
	-webkit-text-stroke: 0.06em #000000; paint-order: stroke fill;
}
/* La capa elegida se marca con un filo: es a quien obedecen la × y el tirador. */
.sticker-capa.is-elegida { outline: 2px dashed var(--accent); outline-offset: 2px; }
.sticker-capa-x, .sticker-capa-asa {
	position: absolute; display: none; padding: 0;
	align-items: center; justify-content: center;
	border: 2px solid var(--surface); border-radius: 50%;
	-webkit-text-stroke: 0; cursor: pointer;
}
.sticker-capa-x {
	top: -0.7rem; right: -0.7rem; width: 1.5rem; height: 1.5rem;
	background: var(--bad, #C0392B); color: #FFFFFF;
	font-size: 0.95rem; line-height: 1; font-weight: 700;
}
.sticker-capa-asa {
	bottom: -0.8rem; right: -0.8rem; width: 1.6rem; height: 1.6rem;
	background: var(--accent); cursor: nwse-resize; touch-action: none;
}
.sticker-capa.is-elegida .sticker-capa-x,
.sticker-capa.is-elegida .sticker-capa-asa { display: flex; }
.sticker-editor-barra { display: flex; gap: 0.5rem; justify-content: center; }
/* EL PINCEL del editor de stickers: el canvas cubre el lienzo entero y por defecto deja
   pasar el dedo — solo lo recibe con el pincel encendido, o arrastrar una capa dejaría de
   funcionar en cuanto se dibujara algo. */
.sticker-pintura {
	position: absolute; inset: 0; width: 100%; height: 100%;
	pointer-events: none; touch-action: none;
}
/* La paleta: los colores, deshacer y el grosor en una fila que se parte si no cabe. */
.sticker-paleta {
	display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
	justify-content: center; margin-top: 0.4rem;
}
.sticker-paleta-colores { display: flex; gap: 0.35rem; }
.sticker-color {
	width: 1.7rem; height: 1.7rem; border-radius: 50%;
	border: 1px solid var(--line); cursor: pointer; padding: 0;
}
.sticker-color.is-activo { box-shadow: 0 0 0 2px var(--accent-text, var(--accent)); }
.sticker-paleta input[type="range"] { flex: 1; min-width: 6rem; accent-color: var(--accent); }

/* La fila de escribir, un punto más alta que antes: el campo y sus iconos crecen un poco y
   todo se pulsa mejor, sin cambiar nada de sitio.
   Y el campo se lleva TODO el hueco que sobra hasta los iconos: antes se quedaba corto y la
   frase se cortaba a media palabra con espacio libre al lado. */
.chat-compositor .chat-campo { flex: 1 1 auto; min-width: 0; margin-right: 0.15rem; }
.chat-compositor .chat-campo input { height: 2.9rem; font-size: 1.05rem; }
.chat-compositor .chat-accion { padding: 0.45rem; }
.chat-compositor .chat-accion svg { width: 27px; height: 27px; }
/* Y el botón de enviar dentro del campo, todo lo grande que cabe ahí dentro. */
.chat-compositor .enviar-inline-btn {
	width: 2.35rem !important; height: 2.35rem !important; right: 0.28rem !important;
}
/* Con el campo VACÍO no hay botón que esquivar, así que el texto usa todo el ancho. El hueco
   vuelve al escribir la primera letra, que es cuando aparece el botón de enviar: el salto se
   lo come la propia transición y a cambio la frase de "Escribe a…" cabe entera. */
.chat-compositor .enviar-inline input { padding-right: 3rem !important; }
.chat-compositor .enviar-inline:has(input:placeholder-shown) input { padding-right: 0.9rem !important; }

/* El punto de "en línea", junto al nombre de tu pareja en la cabecera del chat. Verde y
   pequeño: es un dato de fondo, no una alarma. */
/* "Últ. vez hoy a las 14:32", debajo del nombre y en pequeño: es un dato de cortesía, no el
   título de la pantalla. Se turna con el punto verde — nunca se ven los dos, porque dicen lo
   mismo mirado de dos maneras. Hoy y ayer se dicen con su nombre; de ahí para atrás, la
   fecha. */
.topbar-visto {
	display: block; font-size: 0.7rem; font-weight: 400; line-height: 1.2;
	color: var(--muted); letter-spacing: 0;
}
.topbar-visto[hidden] { display: none; }
.topbar-enlinea {
	display: inline-block; width: 0.6rem; height: 0.6rem; margin-left: 0.45rem;
	border-radius: 50%; background: var(--ok); vertical-align: middle;
	box-shadow: 0 0 0 2px var(--surface);
}

/* SU CARA en la cabecera de cualquier sección (fuera del chat, que lleva las dos). El punto
   verde CUELGA de la cara, con un aro del color de la barra: sin el aro, sobre una foto clara
   el verde se pierde y sobre una oscura parece un defecto de la imagen. */
.topbar-pareja {
	position: relative; flex-shrink: 0; display: flex;
	background: none; border: none; padding: 0; cursor: pointer;
}
.topbar-pareja[hidden] { display: none; }
.topbar-pareja-punto {
	position: absolute; right: -1px; bottom: -1px;
	width: 0.65rem; height: 0.65rem; border-radius: 50%;
	background: var(--ok); box-shadow: 0 0 0 2px var(--bg, var(--surface));
}
.topbar-pareja-punto[hidden] { display: none; }

/* LA NUBE DE SU ESTADO, colgando de su cara (la de la izquierda de la barra). Flota por
   encima del contenido y NO le reserva sitio: perder esa franja en todas las secciones por
   algo que ocupa dos dedos en una esquina era peor que taparla un momento. Las bolitas de la
   cola tienen que TOCAR la cara, o no dice de quién es. */
.topbar-nube {
	position: absolute; left: 0.9rem; top: calc(100% + 0.5rem);
	max-width: min(16rem, calc(100vw - 2rem));
	padding: 0.45rem 0.8rem; border-radius: 1.1rem;
	background: var(--surface); color: var(--text); border: 1px solid var(--line);
	box-shadow: var(--shadow);
	font: inherit; font-size: 0.85rem; line-height: 1.3; text-align: left; cursor: pointer;
	--reaccion-tam: 1.3rem;
}
.topbar-nube[hidden] { display: none; }
/* Con disco de reacción, el bloque de LA REACCIÓN convierte al padre en `relative` (para ser
   su marco) y eso la metía en la fila de la barra. `absolute` también es marco para el disco,
   así que aquí se sube el peso y se queda flotando. */
.topbar > .topbar-nube { position: absolute; }
.topbar-nube::before, .topbar-nube::after {
	content: ""; position: absolute; border-radius: 50%;
	background: var(--surface); border: 1px solid var(--line);
}
.topbar-nube::before { width: 0.55rem; height: 0.55rem; left: 0.55rem; top: -0.45rem; }
.topbar-nube::after { width: 0.32rem; height: 0.32rem; left: 0.3rem; top: -0.8rem; }
/* El texto en su propio elemento, recortado a tres líneas: una frase larga no puede tapar
   media pantalla. */
.topbar-nube-texto {
	display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
/* El menú de la nube: reaccionar y ocultar. Pegado debajo de la nube, como un menú flotante. */
.nube-menu {
	/* El `top` lo pone app.js al abrirlo, justo debajo de la nube: la nube mide una, dos o
	   tres líneas según la frase, y un número fijo la taparía o dejaría un hueco. */
	position: absolute; left: 0.9rem; top: 100%; z-index: 2;
	display: grid; gap: 0.4rem; padding: 0.55rem;
	background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
	box-shadow: 0 12px 30px rgba(0, 0, 0, 0.16);
}
.nube-menu[hidden] { display: none; }
.nube-menu-emojis { display: flex; gap: 0.2rem; }
.nube-menu-emoji {
	width: 2.3rem; height: 2.3rem; border-radius: 50%; border: none; cursor: pointer;
	background: none; font-size: 1.35rem; line-height: 1;
}
.nube-menu-emoji.is-selected { background: var(--accent-soft); }
.nube-menu-accion {
	background: none; border: none; padding: 0.35rem 0.4rem; cursor: pointer; text-align: left;
	font: inherit; font-size: 0.85rem; color: var(--text);
}

/* LLAMAR, en la ficha de los dos: una píldora suave debajo de lo suyo, no un botón que
   compita con Guardar. */
.losdos-llamar {
	display: inline-flex; align-items: center; gap: 0.3rem; margin-top: 0.2rem;
	padding: 0.25rem 0.7rem; border-radius: 999px;
	background: var(--accent-soft); color: var(--accent-text, var(--accent));
	font-size: 0.78rem; font-weight: 600; text-decoration: none;
}
.losdos-llamar[hidden] { display: none; }

/* LO QUE ESTÁ ESCUCHANDO EN SPOTIFY. En su cara, una nota que cuelga de la esquina de ARRIBA
   (abajo ya está el punto verde); en la ficha, la canción con su portada, que abre Spotify. */
.topbar-pareja-musica {
	position: absolute; right: -0.35rem; top: -0.35rem;
	width: 1.05rem; height: 1.05rem; border-radius: 50%;
	display: grid; place-items: center; font-size: 0.62rem; line-height: 1;
	background: #1db954; color: #fff; box-shadow: 0 0 0 2px var(--bg, var(--surface));
}
.topbar-pareja-musica[hidden] { display: none; }
.topbar-pareja-musica.is-pausa { background: var(--muted); }
.losdos-escuchando {
	display: flex; align-items: center; gap: 0.45rem; margin-top: 0.25rem; max-width: 100%;
	padding: 0.3rem 0.55rem 0.3rem 0.3rem; border-radius: var(--radius-sm);
	background: var(--accent-soft); color: var(--text); text-decoration: none;
	font-size: 0.75rem; line-height: 1.25; text-align: left;
}
.losdos-escuchando[hidden] { display: none; }
.losdos-escuchando img { width: 2.1rem; height: 2.1rem; border-radius: 4px; object-fit: cover; flex-shrink: 0; }
.losdos-escuchando span { min-width: 0; overflow: hidden; }
.losdos-escuchando b, .losdos-escuchando small { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.losdos-escuchando small { color: var(--muted); }

/* La galería de widgets (/relaciones/widgets): etiquetas para distinguir lo que YA es un
   widget compartido de lo que sigue copiado en cada pantalla. */
/* El menú de la galería, pegado al techo: se salta de un widget a otro sin volver arriba. */
.widgets-nav {
	position: sticky; top: 0; z-index: 3; background: var(--bg, var(--surface));
	display: flex; gap: 0.35rem; flex-wrap: wrap;
	padding: 0.6rem 0; margin-bottom: 0.4rem;
}
.widgets-nav .chip { text-decoration: none; }
/* El menú de la galería de widgets: todas sus páginas, siempre a la vista, para no tener que
   recordar direcciones. Se desplaza a lo ancho cuando haya más de las que caben. */
.widgets-nav {
	display: flex; gap: 0.35rem; overflow-x: auto; scrollbar-width: none;
	margin: 0 0 1rem; padding-bottom: 0.2rem;
}
.widgets-nav::-webkit-scrollbar { display: none; }
.widgets-nav .chip { flex: 0 0 auto; text-decoration: none; }

/* La galería lleva su propio margen lateral: el contenido llegaba al borde de la pantalla y
   se leía pegado al canto. */
.widgets-page { padding-left: 1.1rem; padding-right: 1.1rem; }
/* Los chips del menú se salen del margen a propósito, para que se puedan desplazar de canto
   a canto, y recuperan el hueco por dentro. */
.widgets-page .widgets-nav { margin-left: -1.1rem; margin-right: -1.1rem; padding: 0 1.1rem 0.2rem; }

/* La galería: títulos de sección con aire por encima y del color del acento, y las tarjetas
   separadas entre sí — pegadas se leían como una sola lista larga. */
.widget-cat {
	margin: 2rem 0 0.8rem; font-size: 0.8rem; font-weight: 700;
	text-transform: uppercase; letter-spacing: 0.08em;
	color: var(--accent-text, var(--accent));
	scroll-margin-top: 4.5rem;
}
.widget-cat:first-of-type { margin-top: 1rem; }
.widgets-indice { margin: 0 0 1.5rem; }
.widgets-indice ul { margin: 0.4rem 0 0; padding-left: 1.1rem; }
.widgets-indice li { margin-bottom: 0.15rem; }
/* El recuadro de muestra: algo a lo que reaccionar, para probar el selector como se usa. */
.widgets-demo {
	display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
	background: var(--tint); border-radius: var(--radius-sm);
	padding: 0.8rem 0.9rem; margin: 0.6rem 0;
}
/* Y si es de los que se mantienen pulsados, hay que quitarle al navegador SUS gestos: en
   iOS, mantener pulsado un texto selecciona la palabra y saca "Copiar / Buscar", y el gesto
   nuestro no llega a nacer. Las burbujas del chat lo llevan por eso mismo. */
.widgets-demo-longpress {
	-webkit-user-select: none; user-select: none;
	-webkit-touch-callout: none; touch-action: manipulation; cursor: pointer;
}
/* Cada tarjeta lleva SU propio margen abajo, no uno que dependa de qué tenga al lado: entre
   algunas hay hojas de muestra escondidas por medio, y con el selector de hermano adyacente
   unas se separaban y otras no. */
.widgets-page .card { margin-bottom: 0.9rem; }
.widget-nombre { margin: 0 0 0.35rem; font-weight: 700; font-size: 1.05rem; }
/* Un MARCO para enseñar en la galería las piezas que en la app van FIJAS a la pantalla: la
   barra de abajo, la cabecera. Lo único que cambia dentro es que dejan de estar fijas — ni
   colores, ni tamaños, ni marcado: se incluye el partial de verdad, no una copia. Sin esto
   la única forma de enseñarlas era dibujarlas a mano, que es lo que la galería no puede
   hacer. Si mañana hay otra pieza fija, se añade su clase a la línea de abajo. */
.widgets-marco {
	position: relative; overflow: hidden;
	border: 1px dashed var(--line); border-radius: var(--radius-sm);
}
.widgets-marco > .bottomnav, .widgets-marco > .topbar { position: static; }

.widget-tag {
	display: inline-block; margin-left: 0.4rem; padding: 0.1rem 0.4rem;
	border-radius: 999px; background: var(--tint); color: var(--muted);
	font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
/* Los dos tonos salen de los TOKENS de la app (--ok y --warn), no de dos hex escritos aquí:
   así siguen al modo oscuro y a cualquier cambio de paleta como todo lo demás. */
.widget-tag--ok { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }
.widget-tag--todo { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }

/* ---- Selector de emojis: buscador, categorías y rejilla ------------------------------- */
.emojipicker { display: grid; gap: 0.5rem; }
.emojipicker-buscar {
	width: 100%; box-sizing: border-box;
	/* Alto explícito y line-height propio: heredando los de la hoja el campo salía cortado
	   por abajo, con el texto pegado al borde. */
	height: 2.9rem; line-height: 2.9rem; padding: 0 0.9rem;
	font: inherit; font-size: 1rem;
	border: 1px solid var(--line); border-radius: var(--radius-control);
	background: var(--surface); color: var(--text); -webkit-appearance: none;
}
/* Los chips de categoría, pegados al techo: se salta de una a otra sin volver arriba. */
.emojipicker-cats {
	position: sticky; top: -1rem; z-index: 2; background: var(--surface);
	display: flex; gap: 0.3rem; overflow-x: auto; scrollbar-width: none;
	margin: -0.2rem -1.4rem 0; padding: 0.4rem 1.4rem 0.5rem;
}
.emojipicker-cats::-webkit-scrollbar { display: none; }
.emojipicker-cats .chip { flex: 0 0 auto; font-size: 1.05rem; padding: 0.35rem 0.7rem; }
.emojipicker-seccion { margin-bottom: 0.6rem; }
.emojipicker-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.3rem; }
.emojipicker-btn {
	background: none; border: none; cursor: pointer; padding: 0;
	font-size: 1.6rem; line-height: 1; height: 2.9rem; border-radius: var(--radius-sm);
	display: flex; align-items: center; justify-content: center;
}
.emojipicker-btn:active { background: var(--tint); }
/* Esconder es una CLASE, no el atributo `hidden`: estos botones tienen su propio display y
   ganaría al que pone `hidden`. */
.emojipicker-btn.is-oculto, .emojipicker-seccion.is-oculto { display: none; }
.emojipicker-titulo {
	margin: 0.4rem 0 0.3rem;
	font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
	letter-spacing: 0.04em; color: var(--muted);
}
/* Dentro de una categoría el título sobra: ya lo dice el chip elegido. */
.emojipicker--una .emojipicker-titulo { display: none; }
.emojipicker-vacio { margin: 0.6rem 0 0; color: var(--muted); font-size: 0.85rem; text-align: center; }

/* LOS DOS TICS, al lado de la hora y solo en lo tuyo. UNO GRIS: está en el servidor. DOS
   AZULES: lo ha leído. Antes solo existía el de leído, con el argumento de que "un mensaje
   que sale del móvil llega" — con mala cobertura eso no es verdad, y sin el gris no hay
   forma de distinguir "todavía no lo ha visto" de "no ha salido de aquí".
   Sigue sobre una PASTILLA BLANCA y no suelto: la burbuja tuya es roja, y ni un gris ni un
   azul se leen encima de ella. La pastilla se ensancha sola con el segundo tic.
   El azul es el mismo de la app (Tema.leido) — es el único azul que hay, y el que todo el
   mundo ya tiene aprendido de otra app.
   Los tics son SVG y no el carácter "✓": el trazo es el que se pide, no el que traiga la
   fuente del móvil. */
.chat-check {
	display: inline-flex; align-items: center; justify-content: center;
	height: 1.4em; min-width: 1.4em; padding: 0 0.22em; margin-left: 0.4rem;
	/* 1.4em de la hora: el alto de su línea de texto, no solo de sus letras. */
	border-radius: 999px; background: #FFFFFF; color: #8A8A8A;
	vertical-align: -0.15em;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.chat-check svg { width: 0.72em; height: 0.72em; display: block; }
.chat-check.is-leido { color: #2A93E0; }
/* El doble es más ancho que alto (viewBox 28×24): sin esto se aplastaría al cuadrado del
   sencillo y los dos tics saldrían pegados uno encima del otro. */
.chat-check.is-leido svg { width: 0.95em; }

/* DÓNDE ESTÁ, EN VIVO: la barra de encima del campo de escribir. Una por persona que esté
   compartiendo —la suya, la tuya, o las dos— y se va sola cuando se acaba el tiempo. No es
   una burbuja a propósito: un punto que se mueve no se queda en el hilo, y como burbuja
   habría que ir a buscarlo hacia arriba cada vez. */
.chat-ubicacion { display: grid; gap: 0.3rem; margin: 0 0 0.4rem; }
.chat-ubicacion-fila {
	display: flex; align-items: center; gap: 0.5rem;
	padding: 0.45rem 0.6rem; border-radius: var(--radius-control);
	background: var(--tint); border: 1px solid var(--line);
}
.chat-ubicacion-texto {
	display: flex; align-items: center; gap: 0.5rem; min-width: 0; flex: 1 1 auto;
	color: var(--text); text-decoration: none;
}
.chat-ubicacion-texto > span { display: flex; flex-direction: column; min-width: 0; }
.chat-ubicacion-texto strong {
	font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-ubicacion-texto small { font-size: 0.72rem; color: var(--muted); }
/* La tuya se distingue por el color del icono, no por otra caja: es la misma información
   mirada desde el otro lado. */
.chat-ubicacion-fila--mia .chat-ubicacion-texto { color: var(--accent-text, var(--accent)); }
/* El interruptor de "avisos sin el texto": la fila entera se toca, con la explicación
   debajo. Un cuadradito suelto al que hay que acertar no se lee, y esto se decide leyendo. */
.avisos-sintexto {
	display: flex; align-items: flex-start; gap: 0.6rem;
	margin: 0.9rem 0 0; padding-top: 0.9rem; border-top: 1px solid var(--line);
	cursor: pointer;
}
.avisos-sintexto input { flex: 0 0 auto; width: 1.1rem; height: 1.1rem; margin-top: 0.15rem; accent-color: var(--accent); }
.avisos-sintexto > span { display: grid; gap: 0.15rem; min-width: 0; }
.avisos-sintexto strong { font-size: 0.9rem; }
.avisos-sintexto small { font-size: 0.78rem; color: var(--muted); line-height: 1.35; }

/* La caja de lo que NO se deshace. Sin fondo de alarma: el borde basta para decir que esto
   es de otra clase, y un recuadro rojo a media pantalla asusta cada vez que pasas por
   delante, que es todos los días. */
.card--peligro { border-color: rgba(192, 57, 43, 0.35); }
.card--peligro .fact-label { color: #C0392B; }

.chat-ubicacion-parar {
	flex: 0 0 auto; padding: 0.25rem 0.7rem; border-radius: 999px;
	border: 1px solid var(--line); background: var(--surface); color: var(--muted);
	font: inherit; font-size: 0.78rem; cursor: pointer;
}

/* Aquí vivían las reglas del "un solo vistazo": el sobre cerrado de la burbuja, el botón del
   1 de las pantallas de envío y la capa negra que lo abría. El concepto se ha quitado entero
   de la app. */
/* VOLVER ABAJO DEL TODO. Flotante sobre la conversación, justo encima de la fila de
   escribir. Nace escondido y solo aparece cuando estás lejos del final: cerca sobraría —
   ya ves el último mensaje— y un botón que está siempre deja de significar nada. */
.chat-bajar {
	position: absolute; left: 50%; bottom: calc(100% + 0.6rem); z-index: var(--z-flotante);
	width: 2.9rem; height: 2.9rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
	background: var(--surface); color: var(--text);
	border: 1px solid var(--line); box-shadow: var(--shadow); cursor: pointer;
	transform: translate(-50%, 0.6rem); opacity: 0; pointer-events: none;
	transition: opacity 0.18s ease-out, transform 0.18s ease-out;
}
.chat-bajar.is-visible { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
/* LA PÍLDORA DEL DÍA: flotando arriba del hilo mientras lees hacia atrás, con el día por el
   que vas. Pegada (sticky) a lo alto de <main>, que es el que se desplaza, y en una caja de
   alto cero: no empuja la conversación, va por encima. Del tamaño de un botón y con su
   icono — a letra de etiqueta nadie la lee como algo que se toque. */
.chat-dia-pildora-caja {
	position: sticky; top: 0.4rem; height: 0; z-index: var(--z-flotante);
	display: flex; justify-content: center;
}
.chat-dia-pildora {
	display: inline-flex; align-items: center; gap: 0.35rem; height: 2.2rem;
	padding: 0 0.9rem; border-radius: 999px; cursor: pointer;
	background: var(--surface); color: var(--accent); font: inherit; font-size: 0.85rem; font-weight: 600;
	border: 1px solid var(--line); box-shadow: var(--shadow);
	opacity: 0; transform: translateY(-0.4rem) scale(0.94); pointer-events: none;
	transition: opacity 0.18s ease-out, transform 0.18s ease-out;
}
.chat-dia-pildora.is-visible { opacity: 1; transform: none; pointer-events: auto; }
/* El índice de días: una fila por día, la fecha dicha arriba y cuántos mensajes debajo. */
.chat-dias-lista { display: grid; margin-top: 0.4rem; }
.chat-dias-fila {
	display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
	width: 100%; padding: 0.65rem 0.2rem; text-align: left; cursor: pointer;
	background: none; border: 0; border-bottom: 1px solid var(--line); font: inherit; color: var(--text);
}
.chat-dias-fila:last-child { border-bottom: 0; }
.chat-dias-fila > span:first-child { display: grid; gap: 0.1rem; }
.chat-dias-fecha { font-size: 0.95rem; }
.chat-dias-fecha::first-letter { text-transform: uppercase; }
.chat-dias-cuantos { font-size: 0.75rem; color: var(--muted); }
.chat-dias-flecha { color: var(--muted); font-size: 1.2rem; line-height: 1; }
/* DENUNCIAR (partials/denunciar.html): los cuatro motivos, uno por fila y enteros. */
.denuncia-subtitulo { margin: 0.8rem 0 0.4rem; font-size: 0.8rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.denuncia-motivos {
	display: grid; border: 1px solid var(--line); border-radius: var(--radius-sm, 12px);
	background: var(--surface); padding: 0 0.8rem;
}
.denuncia-motivo {
	display: flex; align-items: flex-start; gap: 0.6rem; padding: 0.6rem 0; cursor: pointer;
	border-bottom: 1px solid var(--line);
}
.denuncia-motivo:last-child { border-bottom: 0; }
.denuncia-motivo input { margin-top: 0.2rem; width: 1.05rem; height: 1.05rem; accent-color: var(--accent); flex: 0 0 auto; }
.denuncia-motivo span { display: grid; gap: 0.1rem; }
.denuncia-motivo strong { font-size: 0.92rem; font-weight: 500; color: var(--text); }
.denuncia-motivo small { font-size: 0.78rem; color: var(--muted); }
.denuncia-recibida { margin: 0; font-size: 0.92rem; color: var(--text); }

/* Una hoja CORTA: la que solo lleva un menú de tres opciones, no una pantalla entera. */
.sheet-panel--corto { max-height: 70vh; }
/* Una opción de un menú en hoja: una fila ancha, tocable de lado a lado. En un móvil, una
   fila entera se acierta sin mirar; un botón pequeño, no. */
.lista-accion {
	display: block; width: 100%; text-align: left;
	padding: 0.8rem 0.2rem; border: 0; border-bottom: 1px solid var(--line);
	background: transparent; color: var(--text); font: inherit; font-size: 0.95rem;
	cursor: pointer;
}
.lista-accion:last-child { border-bottom: 0; }
.lista-accion.is-active { color: var(--accent); font-weight: 600; }
.lista-accion--peligro { color: #C0392B; }

/* LA FILA DE CARPETAS del cajón de stickers: justo debajo de Stickers/GIF, siempre visible.
   "Todos" delante, los grupos detrás, y al final el "+" de crear uno. Se desplaza a lo
   ancho: con diez grupos apilados, la rejilla empezaría a media pantalla. */
.chat-stickers-grupos {
	flex: 0 0 auto;
	display: flex; gap: 0.35rem; overflow-x: auto; padding: 0 0 0.35rem;
	scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.chat-stickers-grupos::-webkit-scrollbar { display: none; }
.chat-stickers-grupo {
	flex: 0 0 auto; padding: 0.25rem 0.7rem; border-radius: 999px;
	border: 1px solid var(--line); background: transparent; color: var(--muted);
	font: inherit; font-size: 0.8rem; cursor: pointer; white-space: nowrap;
}
.chat-stickers-grupo.is-active { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }
/* El "+" de crear grupo: redondo, del alto de las pestañas, y al final de la fila. */
.chat-stickers-grupo--nuevo {
	display: inline-flex; align-items: center; justify-content: center;
	width: 1.9rem; padding: 0; font-size: 1rem; line-height: 1;
}
/* Las secciones DE DENTRO del cajón ("Recientes", "Todos"): un rótulo de bloque, no una
   pestaña. Van en la rejilla, unas debajo de otras. */
.chat-stickers-seccion {
	display: block; margin: 0.5rem 0 0.25rem; font-size: 0.72rem; text-transform: uppercase;
	letter-spacing: 0.04em; color: var(--muted);
}
/* La previa del sticker dentro de su menú: para saber de cuál estás decidiendo. */
.sticker-menu-previa {
	display: block; width: 5rem; height: 5rem; object-fit: contain; margin: 0 auto 0.6rem;
}
.sticker-mover-lista { display: flex; flex-direction: column; }

/* El resumen del buscador y, a su derecha, el atajo a favoritos. */
.buscar-resumen {
	display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
	margin: 0.5rem 0 0;
}
.buscar-favoritos {
	display: inline-flex; align-items: center; gap: 0.3rem;
	padding: 0.3rem 0.7rem; border: 1px solid var(--line); border-radius: 999px;
	background: transparent; color: var(--muted); font: inherit; font-size: 0.85rem;
	cursor: pointer; white-space: nowrap;
}
.buscar-favoritos.is-selected { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }
.buscar-favoritos.is-selected .chip-num { background: rgba(255, 255, 255, 0.22); color: #FFFFFF; }
/* La marca de guardado en una fila de resultado: a la derecha, callada, y solo cuando lo
   está. Es una marca, no un botón — guardar es la pulsación larga. */
.buscar-resultado-fav { margin-left: auto; padding-left: 0.5rem; color: var(--accent); display: flex; align-items: center; }

/* UN ENLACE en la tira de fotos del día. Con portada se ve como una foto y solo lo delata el
   eslabón de la esquina; sin portada, el hueco lleva escrito su sitio. */
.fotos-enlace-marca {
	position: absolute; top: 0.25rem; left: 0.25rem; z-index: 1;
	width: 1.25rem; height: 1.25rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
	background: rgba(0, 0, 0, 0.55); color: #FFFFFF;
}
.fotos-enlace-sitio {
	position: absolute; inset: 0; padding: 0.5rem;
	display: flex; align-items: center; justify-content: center; text-align: center;
	font-size: 0.72rem; line-height: 1.25; color: var(--muted);
	background: var(--tint); border-radius: var(--radius-sm);
	overflow: hidden; word-break: break-word;
}
/* El botón de pegar un enlace va al lado del "+" y con menos peso: añadir una foto es lo
   que se hace casi siempre. */
.fotos-anadir--enlace { color: var(--muted); }

/* LA TARJETA DE UN ENLACE, dentro de la burbuja. Ocupa todo el ancho de la burbuja y se
   apoya en un fondo apenas distinto: es una cosa aparte del mensaje, pero del mismo mensaje.
   El eslabón junto al sitio es lo que la distingue de una foto de un golpe de vista. */
.chat-enlace {
	display: block; margin: 0 0 0.4rem; border-radius: 0.6rem; overflow: hidden;
	background: rgba(127, 127, 127, 0.14); color: inherit; text-decoration: none;
}
.chat-enlace-portada { display: block; width: 100%; max-height: 9rem; object-fit: cover; }
.chat-enlace-cuerpo { display: block; padding: 0.5rem 0.6rem; }
.chat-enlace-sitio {
	display: flex; align-items: center; gap: 0.15rem;
	font-size: 0.72rem; opacity: 0.75; text-transform: lowercase;
}
.chat-enlace-titulo {
	display: block; margin-top: 0.15rem; font-weight: 600; font-size: 0.9rem; line-height: 1.3;
	/* Dos líneas y basta: un título de seis líneas tapa la conversación. */
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.chat-enlace-desc {
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
	margin-top: 0.1rem; font-size: 0.8rem; opacity: 0.8; line-height: 1.35;
}

/* LA HOJA DE SUBIR FOTO, la misma para toda la app. La foto vive en su propia caja porque
   ahí es donde se enganchará el recorte: si estuviera suelta en el cuerpo, recortar obligaría
   a tocar la estructura de la hoja. */
.subirfoto-caja {
	position: relative; background: var(--tint); border-radius: var(--radius-sm);
	display: flex; align-items: center; justify-content: center; min-height: 12rem;
}
.subirfoto-caja img { width: 100%; max-height: 45vh; object-fit: contain; border-radius: var(--radius-sm); }

/* La caja del vídeo, para colgarle la duración en una esquina. */
.chat-video-caja { position: relative; display: inline-block; line-height: 0; }
.chat-video-duracion {
	position: absolute; left: 0.5rem; bottom: 0.5rem;
	background: rgba(0, 0, 0, 0.6); color: #FFFFFF;
	font-size: 0.72rem; font-weight: 600; line-height: 1;
	padding: 0.2rem 0.4rem; border-radius: 999px;
	font-variant-numeric: tabular-nums; pointer-events: none;
}

/* Un vídeo-mensaje en el hilo: cuadrado y redondo, como una nota de vídeo de WhatsApp. */
.chat-video {
	display: block; width: 13rem; max-width: 100%; aspect-ratio: 1;
	object-fit: cover; border-radius: 1rem; background: #000;
}
/* Grabando: la previa tapa la pantalla, con el tiempo y qué hacer para mandarlo. La imagen
   va espejada, que es como uno se ve y como lo hace cualquier cámara frontal. */
.chat-video-capa {
	position: fixed; inset: 0; z-index: var(--z-visor, 90);
	background: #000; display: flex; flex-direction: column;
	align-items: center; justify-content: center; gap: 0.8rem;
}
.chat-video-previa {
	width: 78vw; height: 78vw; max-width: 22rem; max-height: 22rem;
	object-fit: cover; border-radius: 50%; transform: scaleX(-1);
}
.chat-video-tiempo { margin: 0; color: #FFFFFF; font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.chat-video-botones { display: flex; gap: 0.8rem; margin-top: 0.4rem; }

/* Un archivo dentro de una burbuja: icono, nombre y a descargar. Hereda el color de la
   burbuja, así que se lee igual en la tuya (blanco sobre acento) y en la suya. */
.chat-archivo {
	display: flex; align-items: center; gap: 0.5rem; min-width: 0;
	color: inherit; text-decoration: none;
}
.chat-archivo-icono {
	flex: 0 0 auto; width: 2rem; height: 2rem; border-radius: 0.5rem;
	display: flex; align-items: center; justify-content: center;
	background: rgba(127, 127, 127, 0.18);
}
.chat-archivo-nombre {
	min-width: 0; font-size: 0.9rem; font-weight: 600;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
	text-decoration: underline; text-underline-offset: 0.15em;
}

/* Aquí estaba .topbar-lupa, la lupa que solo salía en la cabecera del chat. Ahora la lupa
   vive con la campanita (.buscar-btn) y sale en TODAS las pantallas: buscar se pide desde
   donde estés, igual que los avisos. */
/* Las pestañas de buscar: fila propia, encima del campo, y PEGADAS al techo del cuerpo. Al
   enfocar el campo o al llegar resultados, el cuerpo se desplaza solo y las pestañas se iban
   detrás de la cabecera — que es lo que las tapaba. Con sticky no se van nunca: son el mando
   de esta pantalla, no contenido que pase de largo. */
.buscar-tabs {
	/* Se pega a -1rem y se estira hasta los bordes con márgenes negativos, recuperando el
	   relleno del cuerpo con su propio padding. Pegada a top:0 y con el ancho del contenido,
	   los resultados se colaban por la franja de arriba y por los dos lados: el fondo solo
	   tapaba la caja de los chips, no el hueco alrededor. */
	position: sticky; top: -1rem; z-index: 2;
	background: var(--surface);
	display: flex; align-items: center; gap: 0.35rem;
	margin: -1rem -1.4rem 0.6rem; padding: 1rem 1.4rem 0.5rem;
	/* SE PARTEN EN VARIAS LÍNEAS, no se deslizan. Son siete y con los números no caben de
	   largo: deslizándose, las últimas quedaban cortadas contra el borde sin nada que dijera
	   que había más — y la pestaña que no se ve es una pestaña que no existe. Partidas se
	   ven las siete de un vistazo, que es justo lo que se viene a hacer aquí. */
	flex-wrap: wrap; row-gap: 0.35rem;
}
.buscar-tabs .chip { padding: 0.45rem 0.7rem; font-size: 0.85rem; }
.buscar-tabs::-webkit-scrollbar { display: none; }
.buscar-tabs .chip { flex: 0 0 auto; }
/* La raya que separa lo HABLADO (los tipos de mensaje) de lo VIVIDO (citas e hitos, que son
   del calendario). Ocupa una línea entera: así el segundo grupo empieza siempre en su propia
   fila y no se lee como dos pestañas más de mensajes. */
.buscar-tabs-raya { flex: 0 0 100%; height: 1px; background: var(--line); margin: 0.15rem 0; }
/* Los resultados de buscar: cada uno con quién y cuándo encima del texto encontrado. */
.buscar-resultados { display: grid; gap: 0.4rem; margin-top: 0.6rem; }
.buscar-resultado {
	display: block; width: 100%; text-align: left; cursor: pointer;
	background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
	padding: 0.55rem 0.7rem; font: inherit; color: inherit;
}
/* Con miniatura, la fila pasa a dos columnas: la foto manda y el texto va al lado. */
.buscar-resultado--conFoto { display: flex; align-items: center; gap: 0.6rem; }
.buscar-resultado-mini {
	flex: 0 0 auto; width: 3rem; height: 3rem; border-radius: 0.5rem; object-fit: cover;
}
.buscar-resultado-cuerpo { min-width: 0; }
.buscar-resultado-quien {
	display: block; font-size: 0.72rem; font-weight: 700; color: var(--accent-text, var(--accent));
}
.buscar-resultado-texto { display: block; font-size: 0.9rem; color: var(--text); }

/* El cajón de stickers: sube desde el compositor, encima de la barra de navegación.
   ALTO FIJO, no "hasta 45vh". Con el alto dependiendo del contenido, el cajón crecía al
   pasar de una fila a dos y el hilo daba un salto cada vez — y encima cada pestaña medía
   distinto. Aquí manda el sitio, no lo que haya dentro: la cabecera y el pie se quedan
   quietos y lo que se desplaza es la rejilla, tenga cuatro stickers o cuarenta. */
.chat-stickers {
	flex: 0 0 auto; position: relative; z-index: var(--z-nav);
	background: var(--surface); border-top: 1px solid var(--line);
	padding: 0.6rem 0.9rem 0.8rem;
	height: 17rem; display: flex; flex-direction: column; overflow: hidden;
}
/* Los dos cajones SUBEN, no aparecen de golpe. El alto va de 0 a lo suyo y el contenido
   entra con un punto de retraso, que es lo que hace que se lea como una hoja subiendo y no
   como una caja que crece. La clase la pone el JS un fotograma después de quitar el hidden.
   Cerrar hace el camino inverso y el hidden vuelve al terminar. */
.chat-stickers, .chat-panel {
	height: 0; padding-top: 0; padding-bottom: 0;
	transition: height 0.22s cubic-bezier(.22, .61, .36, 1),
		padding 0.22s cubic-bezier(.22, .61, .36, 1);
}
.chat-stickers > *, .chat-panel > * { transition: opacity 0.18s ease 0.06s; opacity: 0; }
.chat-stickers.is-abierto, .chat-panel.is-abierto { height: 17rem; }
.chat-stickers.is-abierto { padding-top: 0.6rem; padding-bottom: 0.8rem; }
.chat-panel.is-abierto { padding-top: 1rem; padding-bottom: 1.2rem; }
.chat-stickers.is-abierto > *, .chat-panel.is-abierto > * { opacity: 1; }
.chat-stickers-cabecera {
	flex: 0 0 auto;
	display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem;
}
/* Dos pestañas dentro del cajón: los stickers quietos y los GIF. Van en la cabecera, donde
   antes estaba el título — el título decía lo que ya se ve, y las pestañas hacen falta. */
.chat-stickers-tabs { display: flex; gap: 0.3rem; }
.chat-stickers-tab {
	background: none; border: none; cursor: pointer; font: inherit;
	font-size: 0.85rem; font-weight: 700; color: var(--muted);
	padding: 0.25rem 0.7rem; border-radius: 999px;
}
.chat-stickers-tab.is-active { background: var(--accent-soft, var(--tint)); color: var(--accent-text, var(--accent)); }
.chat-stickers-rejilla {
	flex: 1 1 auto; min-height: 0;
	overflow-y: auto; overflow-x: hidden; touch-action: pan-y;
	-webkit-overflow-scrolling: touch; overscroll-behavior: contain;
	padding: 0.4rem 0.4rem 0 0;
	/* Esto ya NO es la cuadrícula: es el marco que se desplaza. La cuadrícula la hacen las
	   secciones de dentro (recientes, todos). Cuando era este el grid, los rótulos de
	   sección y las secciones enteras caían como celdas, y "Recientes" salía al lado de un
	   sticker en vez de encima. */
	display: block;
}
/* Cada sección del cajón es una cuadrícula de cuatro que crece hacia abajo. */
.chat-stickers-recientes, .chat-stickers-tira {
	display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; align-content: start;
}
/* El aviso de estado (subiendo, algo ha fallado) no se desplaza con la rejilla: es del cajón
   entero. Debajo no va nada más — el texto que explicaba que los stickers son de los dos
   ocupaba una franja fija para decir algo que se aprende usándolos una vez. */
.chat-stickers > .status { flex: 0 0 auto; }
.chat-sticker-celda { position: relative; }
.chat-sticker-btn {
	width: 100%; aspect-ratio: 1; padding: 0.2rem; cursor: pointer;
	background: var(--tint); border: 1px solid var(--line); border-radius: 0.7rem;
	display: flex; align-items: center; justify-content: center; color: var(--muted);
}
.chat-sticker-btn img { width: 100%; height: 100%; object-fit: contain; }
/* La × de quitar, pequeña y en la esquina: se ve si la buscas y no estorba al mandar. */
.chat-sticker-quitar {
	position: absolute; top: -0.3rem; right: -0.3rem;
	width: 1.3rem; height: 1.3rem; border-radius: 50%; cursor: pointer;
	background: var(--surface); border: 1px solid var(--line); color: var(--muted);
	font-size: 0.9rem; line-height: 1; padding: 0;
	display: flex; align-items: center; justify-content: center;
}
/* El panel del "+": ocupa el sitio del teclado, con las opciones en fila como en cualquier
   app de mensajería — el icono de color dice de qué va cada una sin tener que leerla.
   MISMO ALTO FIJO que el cajón de stickers (17rem): los dos ocupan el mismo hueco, y si uno
   mide distinto que el otro el hilo pega un salto al pasar de uno a otro. Las opciones se
   quedan arriba, donde estaban, en vez de estirarse por el sitio de más. */
.chat-panel {
	flex: 0 0 auto; position: relative; z-index: var(--z-nav);
	background: var(--surface); border-top: 1px solid var(--line);
	padding: 1rem 0.9rem 1.2rem;
	height: 17rem; overflow-y: auto;
	display: flex; gap: 1.4rem; justify-content: center; align-items: flex-start;
}
.chat-panel-opcion {
	display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
	background: none; border: none; padding: 0; cursor: pointer;
	font: inherit; font-size: 0.72rem; color: var(--muted);
}
.chat-panel-icono {
	width: 3.2rem; height: 3.2rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
}
/* La reacción de un mensaje NO tiene estilo propio: es EL disco de la app, el mismo que
   cuelga de una foto o de un gusto. Aquí estuvo escrito aparte —y colocado a la izquierda
   en la burbuja de tu pareja y a la derecha en la tuya—, que es exactamente cómo se acaba
   con seis colocaciones distintas para la misma cosa. Todo lo suyo está en el bloque
   "LA REACCIÓN" (buscar .reaccion-badge), y .chat-reaccion-badge es hoy un alias de ese
   bloque para el marcado que todavía lo escriba así. */
/* La burbuja deja de recortar para que el disco pueda asomar por debajo, y la fila reserva
   ese hueco: si no, el badge se comería el espacio del mensaje siguiente. */
.chat-burbuja, .reto-msg-burbuja { position: relative; overflow: visible; }
.chat-hilo { padding-bottom: 0.4rem; }
/* Los botones de adjuntar, stickers y micro, dentro de la fila de escribir: sin fondo ni
   borde, para que el protagonista siga siendo el sitio donde se escribe — pero en el color
   del texto, no en gris. En gris parecían desactivados, y son tres de las cosas que más se
   tocan de la pantalla. */
.chat-accion {
	flex: 0 0 auto; background: none; border: none; padding: 0.3rem;
	color: var(--text); cursor: pointer; display: flex; align-items: center;
}
/* El resalte al pasar por encima, SOLO donde hay puntero de verdad. En un móvil no existe
   "pasar por encima": al tocar, Safari deja el :hover puesto hasta que tocas en otro sitio,
   y el icono se quedaba encendido como si estuviera seleccionado. */
@media (hover: hover) {
	.chat-accion:hover { color: var(--accent-text, var(--accent)); }
}
/* Al escribir, los botones de la DERECHA del campo se van y el campo se queda con todo el
   ancho: cuando estás escribiendo, lo único que importa es lo que escribes. Vuelven solos al
   soltar el foco.
   Se van encogiendo (max-width a 0) en vez de desaparecer de golpe: así el campo se ensancha
   con ellos en el mismo movimiento, en vez de dar un salto cuando ya no están.
   El "+" de la izquierda se queda: es la puerta a mandar otra cosa, y ahí no estorba. */
.chat-compositor > span ~ .chat-accion {
	max-width: 2.4rem; overflow: hidden;
	transition: max-width 0.3s cubic-bezier(.32, .72, 0, 1),
		padding 0.3s cubic-bezier(.32, .72, 0, 1),
		opacity 0.18s ease,
		transform 0.3s cubic-bezier(.32, .72, 0, 1);
}
/* Se van SOLO cuando has escrito algo, no al tocar el campo: tocarlo y no escribir nada pasa
   constantemente —para leer, para cerrar un cajón— y ver desaparecer los tres botones cada
   vez sería un parpadeo gratis. En cuanto hay una letra, el sitio lo pide el texto.
   Se van ESCALONADOS y hacia la derecha, como si el texto los empujara fuera: los tres a la
   vez se leen como un corte, y de uno en uno se lee como un movimiento. Al volver, el orden
   se invierte solo —el retardo se aplica a la ida— y entran del derecho. */
/* Enviar NO se aparta al escribir: es lo único que quieres tener delante cuando hay texto,
   y va dentro del campo, que se queda. */
.chat-compositor--escrito > span ~ .chat-accion {
	max-width: 0; padding-left: 0; padding-right: 0; opacity: 0;
	transform: translateX(0.5rem) scale(0.7);
}
.chat-compositor--escrito > span ~ .chat-accion:nth-last-child(2) { transition-delay: 0.03s; }
.chat-compositor--escrito > span ~ .chat-accion:nth-last-child(1) { transition-delay: 0.06s; }
/* Una foto en el hilo: la burbuja se ciñe a ella. Sin el padding de una de texto cuando va
   sola, o quedaría un marco de color alrededor de la imagen. */
.chat-foto {
	display: block; width: 100%; max-width: 15rem; border-radius: 0.75rem; object-fit: cover;
}
.chat-burbuja--foto { padding: 0.25rem; }
.chat-burbuja--foto .chat-hora { padding: 0 0.3rem 0.1rem; }
/* FOTO CON TEXTO: la burbuja mide lo que la foto, y el texto se acomoda debajo a ese ancho.
   Sin ancho fijo, la burbuja se estiraba hasta su 78 % por el tamaño natural de la imagen,
   la foto se quedaba en sus 15rem y a la derecha sobraba una franja de color.
   :has y no una clase, porque en un mensaje cifrado la foto llega DESPUÉS de pintar la
   burbuja (pintarAdjuntoCifrado), y así vale para los dos caminos. */
.chat-burbuja:not(.chat-burbuja--sticker):has(.chat-foto) { width: 15rem; max-width: 78%; padding: 0.25rem; }
.chat-burbuja:not(.chat-burbuja--sticker):has(.chat-foto) .chat-foto { max-width: none; }
.chat-burbuja:not(.chat-burbuja--sticker):has(.chat-foto) .chat-burbuja-texto { display: block; padding: 0.35rem 0.45rem 0; }
.chat-burbuja:not(.chat-burbuja--sticker):has(.chat-foto) .chat-hora { padding: 0 0.45rem 0.15rem; }

/* ═══ FOTO DE UN SOLO VISTAZO ══════════════════════════════════════════════════════════
   El sobre cerrado dentro de la burbuja. No hay foto que enseñar —el servidor no manda la
   URL hasta que se abre— así que lo que se pinta es el estado: el "1" y lo que va a pasar
   al tocarlo. Abierta se apaga y deja de responder, que es exactamente lo que le ha pasado. */
.chat-unavez {
	display: flex; align-items: center; gap: 0.6rem; width: 100%;
	background: none; border: none; padding: 0.2rem 0; font: inherit; color: inherit;
	text-align: left; cursor: pointer;
}
.chat-unavez:disabled { cursor: default; opacity: 0.6; }
.chat-unavez-icono {
	display: flex; align-items: center; justify-content: center; flex-shrink: 0;
	width: 1.9rem; height: 1.9rem; border-radius: 50%;
	border: 2px solid currentColor; font-weight: 700; font-size: 0.9rem;
}
.chat-unavez--abierta .chat-unavez-icono { border-style: dashed; }
.chat-unavez-texto { display: flex; flex-direction: column; min-width: 0; }
.chat-unavez-texto strong { font-size: 0.95rem; }
.chat-unavez-texto em { font-style: normal; font-size: 0.78rem; opacity: 0.8; }
/* LA MINIATURA DE LO CITADO. La misma medida en los dos sitios donde sale —la cita de
   dentro de la burbuja y la cinta de "respondes a" encima del campo— porque es la misma
   cosa: si cada uno eligiera la suya, responder a una foto se vería de una manera al
   escribir y de otra al mandarlo. */
.chat-cita-mini {
	width: 2rem; height: 2rem; flex-shrink: 0;
	object-fit: cover; border-radius: 0.3rem;
}
/* Dentro de la burbuja, la cita es una rejilla de dos filas (quién y qué). Con miniatura
   gana una columna a la derecha, y la foto ocupa las dos filas: apilada debajo abriría la
   cita al doble de alto para decir lo mismo. */
.chat-cita:has(.chat-cita-mini) { grid-template-columns: 1fr auto; }
.chat-cita .chat-cita-mini { grid-row: 1 / 3; grid-column: 2; }
/* La casilla de la previa: se lee entera, no es un cuadradito suelto al que hay que
   acertar. Marcar algo que no se puede deshacer se hace leyendo lo que dice. */
.foto-unavez {
	display: flex; align-items: center; gap: 0.5rem;
	font-size: 0.85rem; color: var(--muted); cursor: pointer;
}
.foto-unavez input { width: 1.1rem; height: 1.1rem; accent-color: var(--accent); }
.foto-unavez strong { color: var(--text); }
/* El visor: a pantalla completa, sobre negro y con una sola salida. Ni guardar, ni
   compartir, ni pasar a la siguiente — cualquiera de las tres rompería lo prometido. */
.unavez-visor {
	position: fixed; inset: 0; z-index: var(--z-visor);
	display: flex; align-items: center; justify-content: center;
	background: #000;
}
.unavez-visor img { max-width: 100%; max-height: 100%; object-fit: contain; }
.unavez-visor-aviso {
	position: absolute; top: calc(0.8rem + env(safe-area-inset-top)); right: 0.8rem;
	padding: 0.3rem 0.6rem; border-radius: 999px;
	background: rgba(0,0,0,0.45); color: #fff; font-size: 0.78rem; font-weight: 600;
}
.unavez-visor-cerrar {
	position: absolute; top: calc(0.8rem + env(safe-area-inset-top)); left: 0.8rem;
	width: 2.4rem; height: 2.4rem; border-radius: 50%; border: none;
	background: rgba(0,0,0,0.45); color: #fff; font-size: 1rem; cursor: pointer;
}
/* Mientras se escribe, la barra de abajo desaparece: con el teclado abierto era un cinturón
   de iconos entre lo que escribes y el teclado, y empujaba la conversación fuera de la
   pantalla. Vuelve sola al soltar el campo. */
/* Con el teclado arriba, la barra de abajo se aparta: no hay a dónde navegar mientras se
   escribe, y ahí en medio se comía el sitio entre el campo y el teclado. UNA sola clase para
   toda la app —chat, coach, cualquier campo— puesta por montarAjusteTeclado. */
body.escribiendo .bottomnav { display: none; }
/* El compositor del coach ya no necesita corrección aquí: es sticky al fondo de <main>, y
   <main> encoge y crece solo. Corregirle el "bottom" a mano era el parche de cuando estaba
   fijado al viewport, y esos parches son los que hacían saltar la pantalla. */
/* Y el hilo se pega ABAJO: con pocos mensajes se quedaban arriba del todo, lejos del campo
   de escribir, con media pantalla en blanco en medio. En un chat lo último es lo que se
   viene a leer, así que va junto a donde se responde. */
.chat-hilo { justify-content: flex-end; min-height: 100%; }
body.app-home:has(.chat-hilo) main > .wrap { min-height: 100%; display: flex; flex-direction: column; }
body.app-home:has(.chat-hilo) main > .wrap > .chat-hilo { flex: 1; }
/* El chat no lleva el respiro de arriba y abajo de las demás pantallas: aquí el último
   mensaje tiene que quedar a la misma distancia del campo de escribir que del anterior, y
   esos 2rem de .app-dash eran justo el hueco descompensado que se veía. */
body.app-home:has(.chat-hilo) main > .wrap { padding-block: 0.6rem; }

/* Campos de formulario: la plataforma ya estiliza .form input/select/textarea con los
   tokens de arriba; aquí solo se afina lo que ese estilo genérico no cubre. ------------ */

.form input[type="radio"], .form input[type="checkbox"] {
	width: auto; padding: 0; border: 0; background: none; box-shadow: none; accent-color: var(--accent);
}
.form select {
	appearance: none; -webkit-appearance: none;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2386807A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 1rem;
	padding-right: 2.2rem;
}
.form input, .form select, .form textarea { background-color: var(--surface); }

/* Hoja inferior de "añadir gusto": cabecera y acciones fijas, el cuerpo es lo único que
   hace scroll — así nunca se sale de la pantalla, ni con el teclado abierto en móvil. --- */

/* Hilo del coach: EL MISMO ASPECTO QUE EL CHAT. Era una segunda versión de lo mismo —otro
   radio, otro relleno, otro color de fondo— y una conversación es una conversación: si en el
   chat una burbuja tuya es acento a la derecha con las esquinas así, aquí también.
   Se deja su propio scroll con tope de alto: en el coach la conversación convive con las
   tarjetas de la lectura, y sin tope el campo de escribir se iría al final de una página
   larguísima. Esa es la única diferencia que se gana el sitio. */
.terapia-hilo {
	list-style: none; padding: 0.4rem 0 0; margin: 0;
	display: flex; flex-direction: column; gap: 0.35rem;
	max-height: 24rem; overflow-y: auto; overscroll-behavior: contain;
}
.terapia-msg {
	max-width: 78%; padding: 0.55rem 0.75rem;
	border-radius: 1.1rem; line-height: 1.45; white-space: pre-line;
	font-size: 0.95rem; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
}
/* El coach a la izquierda, sobre superficie y con la esquina de abajo recortada, igual que
   los mensajes de tu pareja: es la otra voz de la conversación. */
.terapia-msg--terapeuta {
	background: var(--surface); align-self: flex-start; border-bottom-left-radius: 0.35rem;
}
/* Y lo tuyo a la derecha en el acento, como en el chat. */
.terapia-msg--mio {
	background: var(--accent); color: #FFFFFF; align-self: flex-end;
	border-bottom-right-radius: 0.35rem;
}
.terapia-msg--mio .fact-label { color: rgba(255, 255, 255, 0.75); }

.terapia-lista { list-style: none; padding: 0; margin: 0.7rem 0 0; display: flex; flex-direction: column; gap: 0.4rem; }
.terapia-lista a {
	display: flex; justify-content: space-between; align-items: center; gap: 0.6rem;
	padding: 0.8rem 1rem; background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm); text-decoration: none; color: inherit;
}
/* El título ocupa lo que sobra y se corta; la fecha y el candado no se encogen nunca. */
.terapia-lista-titulo { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.terapia-lista-meta {
	flex: 0 0 auto; display: flex; align-items: center; gap: 0.35rem;
	font-size: var(--txt-xs); color: var(--accent-text, var(--accent));
}

/* La foto de un reto, a la izquierda de su nombre en la pantalla del día. */
.reto-foto {
	flex: 0 0 auto; width: 1.9rem; height: 1.9rem; border-radius: var(--radius-sm);
	object-fit: cover; display: block;
}

/* Pestaña de una categoría bloqueada: apagada, pero pulsable. Entrar tiene que poder
   hacerse — ver lo que hay dentro es lo que anima a pasar a premium; lo que no se puede es
   abrir los gustos. Por eso NO usa .bloqueado, que además quita las pulsaciones. */
.tab-btn--bloqueada { opacity: 0.55; }
.tab-btn--bloqueada.is-active { opacity: 1; }

/* Bloqueado por el plan gratis: se VE, pero no se toca. Difuminado y en gris, con un candado
   encima. La idea es justo esa — que se note que sigue ahí y que lo que falta es el plan, no
   los datos: nada se ha borrado.
   El pointer-events:none es lo que lo hace de verdad inaccesible; sin él, se abriría igual
   por debajo del difuminado. */
.bloqueado {
	position: relative; pointer-events: none;
	filter: grayscale(1) blur(2px) opacity(0.55);
	user-select: none;
}
.bloqueado-wrap { position: relative; }
.bloqueado-wrap::after {
	/* El candado de trazo de siempre (MividaIconos "candado"), como máscara: un
	   pseudo-elemento no puede llevar un <svg>, y así toma el color acento. */
	content: ""; position: absolute; top: 50%; left: 50%;
	width: 1.3rem; height: 1.3rem; margin: -0.65rem 0 0 -0.65rem;
	background: var(--accent-text); pointer-events: none;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 11h12a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1z'/%3E%3Cpath d='M8 11V7a4 4 0 0 1 8 0v4'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 11h12a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1z'/%3E%3Cpath d='M8 11V7a4 4 0 0 1 8 0v4'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Regla general: nada que se PULSE se puede seleccionar. Botones, enlaces, pestañas, chips,
   días del calendario, la barra de abajo. En un móvil, mantener el dedo sobre cualquiera de
   ellos sacaba el menú de "Copiar / Consultar" de iOS con la palabra marcada en azul — y en
   un botón nadie quiere copiar el texto, quiere pulsarlo.
   Los textos que SÍ se copian — un agradecimiento, una nota, el texto del coach — no llevan
   esto y se siguen pudiendo seleccionar. */
button, .button, .bottomnav-item, .tab-btn, .chip, .tag-chip, .calcell, summary {
	-webkit-user-select: none; user-select: none;
	-webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}

/* Nada de la fila de un reto se selecciona: son botones y etiquetas, no texto que alguien
   quiera copiar. Al mantener el dedo o hacer doble toque, iOS sacaba el menú de "Copiar /
   Consultar" con la palabra marcada en azul, que además tapaba media pantalla.
   Y sin el recuadro gris del toque, que en un botón grande se ve como un borrón. */
.reto-opciones-mia-fila, .reto-opciones-pareja-fila,
.reto-opcion, .reto-opcion--readonly, .reto-fila-puntos {
	-webkit-user-select: none; user-select: none;
	-webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
/* La reacción cuelga de la esquina de la etiqueta marcada y asoma por fuera: sin esto, el
   botón la recortaría por la mitad. */
.reto-opcion, .reto-opcion--readonly { overflow: visible; }

/* Los puntos de cada uno, al final de SU fila: pegados a la derecha, detrás de las
   etiquetas. Arriba, en la cabecera de la tarjeta, había que leer "Tú 3 · Anca 1" y
   averiguar cuál era cuál; aquí cada número está en la fila de quien lo ha ganado. */
.reto-fila-puntos {
	margin-left: auto; flex-shrink: 0; white-space: nowrap;
	font-size: var(--txt-xs); color: var(--muted);
}

/* Lista de entradas de un reto de texto: la ÚLTIMA se ve siempre; las anteriores se
   esconden hasta que se pide "Ver N más". Se oculta con una clase en vez de pintar dos
   listas distintas, para que el trozo de una entrada esté escrito una sola vez. */
.reto-entradas--plegada > .reto-msg-fila:not(.reto-msg-fila--ultima) { display: none; }

/* Un punto en vez de un emoji para marcar el día que tuvo consejo: en una celda de dos
   centímetros, un emoji se lee como un dibujo y compite con el número del día. */
.consejo-punto {
	width: 0.4rem; height: 0.4rem; border-radius: 50%; background: var(--accent); display: block;
}

/* LA PARTE PRIVADA DEL CONSEJO: su caja, con el candado y "Solo para ti" delante. Se tiene
   que saber SIN LEERLO que eso no lo ve la otra persona. El pre-line va en el TEXTO, no en
   la caja, que lleva hijos. */
.consejo-privado {
	margin-top: 0.9rem; padding: 0.7rem 0.9rem; border-radius: var(--radius-sm);
	background: var(--accent-soft); display: flex; flex-direction: column; gap: 0.3rem;
}
.consejo-privado[hidden] { display: none; }
.consejo-privado-marca {
	display: flex; align-items: center; gap: 0.35rem;
	font-size: var(--txt-xs); font-weight: 600; color: var(--accent-text);
}
.consejo-privado-texto { margin: 0; font-size: 0.92rem; line-height: 1.6; white-space: pre-line; }

/* EL BALANCE DE LA PAREJA (coach, "Evolución de pareja"): seis barras que se miran buscando
   el CENTRO. Tú a la izquierda, tu pareja a la derecha, y un punto que se corre hacia quien
   más pone. El servidor manda los dos números; dónde cae el punto lo dice analisisPageData.
   Sin nota ni porcentaje escrito: una barra corrida es una conversación que tener. */
.balance-pareja { display: flex; flex-direction: column; gap: 0.55rem; margin-top: 0.4rem; line-height: 1.3; }
.balance-caras { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
.balance-quien {
	display: flex; align-items: center; gap: 0.4rem;
	font-size: var(--txt-xs); font-weight: 600; color: var(--muted);
}
.balance-cara {
	width: 26px; height: 26px; border-radius: 50%; object-fit: cover; display: block;
	flex: 0 0 auto; background: var(--accent-soft);
}
.balance-fila { display: flex; flex-direction: column; gap: 0.25rem; }
.balance-fila-cabeza { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; }
.balance-icono { width: 1.1rem; text-align: center; font-size: 0.8rem; }
/* Sin datos se DICE: una barra centrada parecería un empate, y un empate a cero no es un
   equilibrio, es que no hay nada. */
.balance-nada { margin-left: auto; font-size: var(--txt-xs); color: var(--muted); }
.balance-barra { position: relative; height: 16px; }
.balance-ventaja { font-size: var(--txt-xs); font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }
.balance-ventaja--mia { color: var(--accent); }
.balance-barra::before {
	content: ""; position: absolute; left: 0; right: 0; top: 4px; height: 8px;
	border-radius: 4px; background: var(--accent-soft);
}
/* La marca del CENTRO, siempre: sin ella no hay contra qué comparar dónde ha caído el punto. */
.balance-centro { position: absolute; left: 50%; top: 0; width: 1px; height: 16px; background: var(--line); }
.balance-tramo {
	position: absolute; top: 4px; height: 8px; border-radius: 4px;
	background: var(--accent); opacity: 0.35;
}
.balance-punto {
	position: absolute; top: 1px; width: 14px; height: 14px; margin-left: -7px; box-sizing: border-box;
	border-radius: 50%; background: var(--accent); border: 2px solid #fff;
}
.balance-nota { margin: 0.2rem 0 0; font-size: var(--txt-xs); color: var(--muted); }
.balance-separador { border: 0; border-top: 1px solid var(--line); margin: 0.9rem 0 0.2rem; }

/* Destello para señalar "es este": cuando llegas desde un aviso, la burbuja se enciende un
   momento y vuelve a lo normal. Se apaga sola — si se quedara encendida dejaría de decir
   cuál es y pasaría a ser un color más.
   El anillo va POR DENTRO (inset). Por fuera se salía de la burbuja y el contenedor que la
   despliega lo recortaba: se veía el borde de arriba y de la derecha, y los otros dos no. */
.reto-msg-fila.resaltado > .reto-msg-burbuja,
.reto-msg-fila.resaltado .reto-msg-burbuja {
	animation: destelloAviso 2.4s ease-out 1;
}
@keyframes destelloAviso {
	0% { box-shadow: inset 0 0 0 0 var(--accent); }
	12% { box-shadow: inset 0 0 0 3px var(--accent); }
	60% { box-shadow: inset 0 0 0 3px var(--accent); }
	100% { box-shadow: inset 0 0 0 0 rgba(197, 44, 43, 0); }
}
@media (prefers-reduced-motion: reduce) {
	.reto-msg-fila.resaltado .reto-msg-burbuja { animation: none; box-shadow: inset 0 0 0 3px var(--accent); }
}

/* Objetivo conseguido: la tarjeta se llena del acento y late un momento. Es el único
   momento del calendario que merece celebrarse, así que se nota de lejos — pero el latido
   para solo, sin quedarse moviéndose para siempre.
   Lleva .card delante porque .card se define MÁS ABAJO en este fichero y, a igualdad de
   peso, gana la última: sin esto el fondo se quedaba blanco y el texto blanco encima —
   la tarjeta se veía vacía. */
.card.objetivo-card--logrado, .objetivo-card--logrado {
	background: var(--accent); color: #FFFFFF; border-color: var(--accent);
	animation: objetivoLatido 0.9s ease-out 2;
}
.objetivo-card--logrado .objetivo-premio { font-size: 1rem; }
/* Un botón claro sobre el fondo del acento: el "Cancelar" del plan premium. Sin esto
   heredaba el blanco del texto de la tarjeta y quedaba blanco sobre blanco. */
.objetivo-card--logrado .button--light { background: #FFFFFF; color: var(--accent-text); border-color: #FFFFFF; }
.objetivo-logrado-pie { margin: auto 0 0; font-size: 0.78rem; opacity: 0.85; }
@keyframes objetivoLatido {
	0% { transform: scale(1); }
	40% { transform: scale(1.03); }
	100% { transform: scale(1); }
}
/* Quien haya pedido menos movimiento en su móvil, no lo tiene. */
@media (prefers-reduced-motion: reduce) {
	.objetivo-card--logrado { animation: none; }
}

/* El objetivo común: una barra que llenan los dos. Es lo primero de la pantalla del
   calendario porque es el marco de todo lo demás — los retos del día suman aquí. */
.objetivo { margin: 0.9rem 0 0; }
.objetivo-cabecera { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; margin: 0; }
/* Mismo tamaño y peso que el título de la tarjeta de al lado: son la misma jerarquía y
   tienen que leerse igual. */
.objetivo-premio { font-weight: 600; font-size: 0.9rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.objetivo-puntos { flex: 0 0 auto; font-weight: 700; color: var(--accent-text, var(--accent)); font-size: 0.78rem; }
/* El progreso en su propia fila. Se lleva el margin-top:auto que antes tenía la barra:
   lo que se pega al fondo de la tarjeta es el bloque de número + barra, para que las dos
   tarjetas de arriba sigan cuadrando por abajo sea cual sea el largo del premio. */
/* ---- Barra bicolor: UNA pieza, dos tamaños --------------------------------------------
   Dos trozos de color dentro de una pista redondeada, para contar un avance hecho ENTRE LOS
   DOS. Había dos versiones —la fina del objetivo y la gruesa de los puntos del día— con las
   mismas reglas escritas dos veces y peleándose por especificidad. Ahora el comportamiento
   común está aquí, una vez, y cada tamaño solo añade lo suyo.
   Los nombres viejos siguen funcionando a propósito: son los que hay en las plantillas, y
   una unificación que obliga a tocar cinco pantallas se queda a medias. Al extraer el widget
   a su partial, los dos pasarán a .barra-dos. */
.barra-dos, .objetivo-barra--dos, .puntos-barra {
	display: flex; border-radius: 999px; overflow: hidden; background: var(--tint);
}
/* La barra ANIMA su ancho solo cuando CAMBIA, no al aparecer. Al cargar la página, las dos
   mitades salían de cero y se abrían delante de tus ojos: en una pantalla que ya sabía el
   resultado, eso no es una animación, es un parpadeo — y con el gesto de pasar de día, que
   recarga, se veía en cada deslizamiento. La clase la pone app.js DESPUÉS del primer
   pintado: entonces sí, marcar un reto mueve la barra y el movimiento cuenta algo. */
.barra-dos > span, .objetivo-barra--dos > span, .puntos-barra-parte { flex: 0 0 auto; }
.barra-dos.is-viva > span, .objetivo-barra--dos.is-viva > span, .puntos-barra.is-viva .puntos-barra-parte {
	transition: width 0.3s ease-out;
}
/* Los extremos de fuera son los únicos que se redondean: dos cápsulas sueltas se leerían
   como dos barras distintas. */
.barra-dos > :first-child, .objetivo-barra--dos > span:first-child { border-radius: 999px 0 0 999px; }
.barra-dos > :last-child, .objetivo-barra--dos > span:last-child { border-radius: 0 999px 999px 0; }
/* El color de cada uno sale del token, nunca escrito a mano: es el mismo azul y el mismo
   rosa que los aros de los avatares y las marcas del calendario. */
.barra-dos-yo, .objetivo-barra--dos > .objetivo-barra-yo { background: var(--color-yo, var(--accent)); }
.barra-dos-pareja, .objetivo-barra--dos > .objetivo-barra-pareja { background: var(--color-pareja, var(--warn)); }
/* Fina: solo cuenta el avance, sin nada dentro. */
.barra-dos--fina { height: 0.5rem; }
/* Gruesa: lleva dentro el avatar y el número de cada uno. */
.barra-dos--gruesa { height: 1.7rem; }

.objetivo-puntos-fila { margin: auto 0 0; }
.objetivo-barra {
	height: 0.5rem; border-radius: 999px; background: var(--tint); overflow: hidden;
}
.objetivo-barra > span {
	display: block; height: 100%; border-radius: 999px; background: var(--accent);
	transition: width 0.4s ease-out;
}
.objetivo-pie { margin: 0.4rem 0 0; font-size: var(--txt-s); }

/* Asistente de configuración: la única tarjeta de Inicio con el filo del acento, porque es
   lo único de esa pantalla que pide una acción. Cuando no queda nada pendiente desaparece,
   y con ella el filo — así el acento no se gasta en algo permanente. */
.paso-card {
	display: block; padding: 1rem 1.2rem; text-decoration: none; color: inherit;
	border: 1.5px solid var(--accent);
}
.paso-eyebrow {
	display: block; font-size: var(--txt-xs); letter-spacing: 0.06em; text-transform: uppercase;
	color: var(--accent-text, var(--accent)); font-weight: 600;
}
.paso-cta { display: block; margin-top: 0.6rem; color: var(--accent-text, var(--accent)); font-weight: 600; font-size: var(--txt-s); }

/* Avisos del terapeuta: lo que hay que tener en cuenta hoy. Sin tarjeta y sin adornos — es
   una lista corta que se lee de un vistazo antes del ejercicio, no una sección propia. */
.avisos-terapeuta { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.avisos-terapeuta li {
	display: flex; gap: 0.6rem; align-items: baseline;
	font-size: var(--txt-m); line-height: 1.5;
	background: var(--tint); border-radius: var(--radius-sm); padding: 0.7rem 0.9rem;
}

/* Acordeón: apartados plegados para ver de un vistazo TODO lo que hay y abrir solo lo que
   interesa. Se usa <details>, que ya sabe abrirse y cerrarse sin JavaScript. */
.acordeon { display: flex; flex-direction: column; gap: 0.6rem; }
.acordeon-item {
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm); overflow: hidden;
}
.acordeon-titulo {
	list-style: none; cursor: pointer; padding: 1rem 1.2rem;
	font-weight: 600; display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
	/* Safari pinta un recuadro gris al tocar cualquier cosa pulsable, y en una tarjeta
	   grande como esta se ve como si la sección se hubiera "seleccionado". Fuera.
	   Y sin selección de texto: al abrir y cerrar rápido se acababa marcando el título. */
	-webkit-tap-highlight-color: transparent;
	-webkit-user-select: none; user-select: none;
}
.acordeon-titulo:active, .acordeon-titulo:focus { background: transparent; outline: none; }
/* Cabecera de una sección que necesita premium: apagada y con candado, pero PULSABLE. Se
   abre para leer qué hay dentro, que es lo que anima a pagar; lo que no hay es contenido. */
.acordeon-titulo--bloqueado { opacity: 0.6; }
.acordeon-titulo--bloqueado[open], details[open] > .acordeon-titulo--bloqueado { opacity: 1; }

.acordeon-nota {
	display: block; margin-top: 0.15rem; font-weight: 400;
	font-size: var(--txt-xs); color: var(--muted); text-transform: none; letter-spacing: 0;
}
.acordeon-titulo::-webkit-details-marker { display: none; }
/* La flecha gira al abrir: dice si hay algo debajo antes de tocarlo. */
.acordeon-titulo::after {
	content: ""; flex: 0 0 auto; width: 0.5rem; height: 0.5rem; margin-right: 0.2rem;
	border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
	/* Al mismo ritmo que el cuerpo al desplegarse, para que sea un solo movimiento. */
	transform: rotate(45deg); transition: transform 0.45s cubic-bezier(.22, .61, .36, 1);
}
.acordeon-item[open] .acordeon-titulo::after { transform: rotate(-135deg); }
.acordeon-cuerpo {
	padding: 0 1.2rem 1.2rem; line-height: 1.7;
}
/* Los saltos de línea del texto del coach SÍ cuentan (viene en párrafos), pero solo en su
   párrafo. Puesto en todo el cuerpo, convertía en líneas en blanco los saltos y tabuladores
   que la plantilla tiene ENTRE elementos: de ahí el hueco enorme antes del calendario. */
.acordeon-cuerpo > p { white-space: pre-line; }

.sheet-overlay {
	/* Por encima de la barra de abajo: una hoja tapa la pantalla mientras está abierta, y la
	   barra ya no es algo flotante que se pueda dejar debajo con un número más bajo. */
	position: fixed; inset: 0; z-index: var(--z-visor);
	display: flex; align-items: flex-end; justify-content: center;
	background: rgba(12, 10, 6, 0.5);
	/* El rebote no se propaga a la página de detrás: sin esto, al arrastrar la hoja hacia
	   abajo el navegador arrancaba ADEMÁS su "soltar para recargar", y se veían los dos
	   movimientos a la vez. */
	overscroll-behavior: contain;
}
.sheet-panel {
	width: 100%; max-width: 32rem; margin: 0;
	height: min(88vh, 88dvh); max-height: min(88vh, 88dvh);
	display: flex; flex-direction: column;
	background: var(--surface); border-radius: var(--radius) var(--radius) 0 0;
	box-shadow: var(--shadow); overflow: hidden;
}
/* La hoja llega hasta abajo del todo: con ella abierta, la barra de navegación se esconde
   (más arriba), así que ya no hay nada a lo que dejarle sitio. */
body.has-bottomnav .sheet-panel { max-height: 100%; }

/* Con una hoja o un visor abiertos, la barra de abajo se esconde. Una hoja ocupa la pantalla
   y no hay a dónde navegar mientras está delante; y dejándola asomar, el final de la hoja
   competía con ella por el mismo trozo de pantalla. Se cierra y vuelve.
   La clase la pone app.js preguntando si la capa OCUPA SITIO de verdad. Antes se preguntaba
   por el atributo hidden con :has(), y como cada sitio cierra a su manera —hidden, display,
   quitando el elemento— la barra se quedaba escondida después de cerrar. */
body.hoja-abierta .bottomnav { display: none; }
/* Una hoja que baja DESDE ARRIBA y ocupa la pantalla entera. Para lo que sustituye a la
   pantalla mientras dura —buscar— en vez de asomarse por debajo: con media hoja, el chat de
   fondo compite con lo que estás buscando.
   El alto va con max-height ADEMÁS de height: la regla normal de las hojas topa a 88vh, y un
   max-height siempre gana a un height por muy inline que esté — por eso "height:100%" solo
   no bastaba. */
.sheet-overlay--arriba { align-items: flex-start; }
/* El panel se fija a la pantalla y punto: con height:100% dependía de cómo estuviera
   montado el fondo de la hoja, y ahí volvía a quedarse a media altura. Fijado arriba, con
   los cuatro bordes puestos, no hay nada que se pueda torcer. */
.sheet-overlay--arriba .sheet-panel {
	position: fixed; top: 0; left: 0; right: 0; bottom: 0;
	width: 100%; height: auto; max-height: none; max-width: none;
	border-radius: 0 0 var(--radius) var(--radius);
	transform: translateY(-100%);
}
.sheet-overlay--arriba.is-open .sheet-panel,
.sheet-overlay--arriba:not([hidden]) .sheet-panel { transform: translateY(0); }
/* El asa se dibuja abajo, que es hacia donde se arrastra para cerrarla. */
.sheet-overlay--arriba .sheet-panel::before { top: auto; bottom: 0.5rem; }
.sheet-header {	flex: 0 0 auto; padding: 1.2rem 1.4rem 0.8rem; border-bottom: 1px solid var(--line);
	display: grid; gap: 0.6rem;
	/* El gesto de arrastrar para cerrar es NUESTRO aquí, así que no se le deja al
	   navegador. Solo en la cabecera: el cuerpo tiene que poder desplazarse. */
	touch-action: none;
	position: relative;
	-webkit-user-select: none; user-select: none;
}
/* La barrita de siempre: sin ella, que la hoja se arrastra hacia abajo no lo adivina nadie. */
.sheet-header::before {
	content: ""; position: absolute; top: 0.5rem; left: 50%; transform: translateX(-50%);
	width: 2.4rem; height: 0.25rem; border-radius: 999px; background: var(--line);
}
.sheet-header h3 { margin: 0; }

/* Al girar el móvil, la app NO gira: se queda en vertical.
   iOS no deja bloquear la rotación desde la web, así que se hace al revés — cuando la
   pantalla se tumba, el contenido se gira 90 grados en sentido contrario y se le cambian
   el alto por el ancho. El resultado es que nada se mueve.
   Solo en pantallas tumbadas Y BAJAS: la altura distingue un móvil de lado de un portátil,
   donde horizontal es lo normal y girar el contenido sería absurdo. */
@media (orientation: landscape) and (max-height: 500px) {
	html { overflow: hidden; }
	body.has-bottomnav {
		position: fixed; top: 0; left: 0;
		width: 100vh; height: 100vw;
		transform-origin: top left;
		transform: rotate(90deg) translateY(-100vh);
	}
}

/* Lista de gastos y de cuentas cerradas: concepto a la izquierda, importe a la derecha y,
   si es tuyo, la aspa para quitarlo. Una línea por gasto — una cuenta se repasa de arriba
   abajo, y con dos líneas por apunte deja de poder repasarse. */
.gastos-lista { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.gastos-lista li {
	display: flex; align-items: center; gap: 0.7rem;
	padding: 0.7rem 0.9rem; background: var(--surface);
	border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.gastos-concepto { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gastos-importe { flex: 0 0 auto; margin-left: auto; font-weight: 700; white-space: nowrap; }
.gasto-borrar {
	flex: 0 0 auto; background: none; border: none; padding: 0.25rem; cursor: pointer;
	color: var(--muted); display: flex; align-items: center;
}

/* TAREAS. La misma fila que un gasto —tarjeta, una línea, la aspa al final— porque son la
   misma clase de cosa: una lista de apuntes que se repasa de arriba abajo. Lo que cambia es
   que aquí la primera columna es la CASILLA, que es el botón: tocar el texto no marca nada,
   que en una lista de recados el gesto de tachar tiene que costar apuntar, no rozar. */
.tareas-lista { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.tareas-lista li {
	display: flex; align-items: center; gap: 0.7rem;
	padding: 0.7rem 0.9rem; background: var(--surface);
	border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.tarea-check {
	flex: 0 0 auto; background: none; border: none; padding: 0; cursor: pointer;
	color: var(--muted); display: flex; align-items: center;
}
.tarea-check.is-hecha { color: var(--accent); }
.tarea-check:disabled { opacity: 0.5; }
.tarea-titulo { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Tachada y apagada: verla tachada es media recompensa. */
.tarea-titulo--hecha { text-decoration: line-through; color: var(--muted); font-weight: 400; }
.tarea-notas { display: block; font-size: 0.82rem; color: var(--muted); }
/* Lo que vence hoy o ya se pasó, en rojo: una fecha gris no distingue "mañana" de "hace
   tres días", que es lo único que se mira de una lista de recados. */
.tarea-urge { color: var(--bad, #C0392B); font-weight: 600; }
.tarea-borrar {
	flex: 0 0 auto; background: none; border: none; padding: 0.25rem; cursor: pointer;
	color: var(--muted); display: flex; align-items: center;
}
/* Lo hecho, plegado y a media luz: ocupa sitio y ya no pide nada. */
.tareas-lista--hechas { margin-top: 0.5rem; opacity: 0.75; }

/* El banner del coach en Inicio: una fila con icono, texto y flecha. Con el filo del acento
   para que se lea como un camino y no como una tarjeta más de las que solo informan. */
.coach-banner {
	display: flex; align-items: center; gap: 0.8rem; margin: 1rem 0 0;
	padding: 0.9rem 1.1rem; border-radius: var(--radius-sm);
	background: var(--surface); border: 1.5px solid var(--accent);
	text-decoration: none; color: inherit;
}
.coach-banner-icono {
	flex: 0 0 auto; width: 2.2rem; height: 2.2rem; border-radius: 50%;
	background: var(--accent); color: #FFFFFF;
	display: flex; align-items: center; justify-content: center;
}
.coach-banner-flecha { flex: 0 0 auto; margin-left: auto; color: var(--accent-text, var(--accent)); font-size: 1.2rem; }

/* El historial de créditos: qué entró y qué se fue, con su fecha. */
.movimientos-lista { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.movimientos-lista li {
	display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
	padding: 0.6rem 0; border-bottom: 1px solid var(--line);
}
.movimientos-lista li:last-child { border-bottom: none; }
.movimiento-cifra { flex-shrink: 0; font-weight: 700; color: var(--muted); }
/* Lo que entra, en el color del acento: en una lista de números negativos, el positivo tiene
   que verse sin buscarlo. */
.movimiento-cifra--suma { color: var(--accent-text, var(--accent)); }

/* La pastilla "Premium" del título de una sección. Va siempre, la tengas o no: contigo dice
   qué estás usando, y sin ti dice qué se abre al pagar. Una etiqueta que solo aparece cuando
   NO puedes usar algo se lee como un reproche. */
.premium-badge {
	display: inline-block; vertical-align: middle; margin-left: 0.4rem;
	padding: 0.1rem 0.45rem; border-radius: 999px;
	background: var(--accent-soft, var(--tint)); color: var(--accent-text, var(--accent));
	font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
}

/* El saldo como pastilla: fondo suave del acento y esquinas redondas. Un dato que cambia y
   que conviene mirar antes de escribir se lee mejor en una pastilla que suelto entre texto,
   igual que las etiquetas de gustos o las reacciones. */
.saldo-badge {
	display: inline-flex; align-items: center; gap: 0.3rem;
	padding: 0.3rem 0.7rem; border-radius: 999px;
	background: var(--accent-soft, var(--tint)); color: var(--accent-text, var(--accent));
	font-size: var(--txt-s); font-weight: 600;
}
/* La tienda es la ACCIÓN, así que va en acento pleno y en blanco: al lado de la pastilla
   suave del saldo se distingue sola cuál se toca y cuál solo informa. Dos pastillas del
   mismo color parecerían dos datos. */
.saldo-badge--boton {
	border: none; cursor: pointer; padding: 0.35rem 0.6rem; font: inherit;
	background: var(--accent); color: #FFFFFF;
}
.saldo-badge--boton:active { opacity: 0.85; }

/* La fila de escribir del coach: fija abajo, justo encima de la barra de navegación, y
   centrada al mismo ancho que el contenido. En un chat, dónde se escribe no se desplaza con
   lo escrito. */
/* El compositor del coach, igual que el del chat: PEGADO al fondo de lo que se desplaza, no
   fijado al viewport. Fijarlo obligaba a calcular a mano su distancia a la barra de abajo y
   a corregirla con una clase cuando salía el teclado — y esos dos números son justo la
   fuente de los saltos que costó tanto quitar del chat. Con sticky no hay cuentas: se queda
   al final de <main>, y <main> ya encoge y crece solo con el teclado.
   Reserva su propio sitio en el flujo, así que tampoco tapa el último mensaje. */
.coach-escribir {
	position: sticky; bottom: 0; z-index: var(--z-flotante); margin-top: auto;
	padding: 0.6rem 1.2rem;
	background: var(--bg); border-top: 1px solid var(--line);
}
.coach-escribir > form, .coach-escribir > p { max-width: 36rem; margin-left: auto; margin-right: auto; }
.coach-escribir > p { margin-top: 0.35rem; margin-bottom: 0; font-size: 0.78rem; }
/* Hueco al final de la página para que la última conversación no quede debajo de la fila. */
.coach-con-escribir { padding-bottom: 5.5rem; }

/* El candado que decide si una sesión es compartida. Va FUERA del campo, a su izquierda,
   igual que el "+" del chat: dentro competía por el sitio del texto y obligaba a apartarlo,
   y las dos pantallas donde se escribe acababan con dos criterios distintos. */
.candado-btn {
	flex: 0 0 auto; background: none; border: none; padding: 0.3rem; cursor: pointer;
	color: var(--muted); display: flex; align-items: center;
}
.candado-btn--abierto { color: var(--accent-text, var(--accent)); }
/* El formulario con candado es una FILA: el candado suelto a la izquierda y el campo
   ocupando el resto, igual que el compositor del chat. El botón de enviar sigue dentro del
   campo, a la derecha, porque pertenece a lo que estás escribiendo. */
.enviar-inline--candado {
	display: flex; align-items: center; gap: 0.5rem; position: static;
}
.enviar-inline--candado .campo-con-enviar { position: relative; flex: 1 1 auto; min-width: 0; }

/* Primera letra en mayúscula y NADA MÁS. Con text-transform:capitalize, "7 de septiembre"
   sale como "7 De Septiembre" — el navegador sube la inicial de cada palabra, incluidas las
   preposiciones. Esto es lo que hace falta para una fecha escrita en español. */
.mayus-inicial { display: inline-block; }
.mayus-inicial::first-letter { text-transform: uppercase; }

/* Hoja que se ajusta a su contenido, pero NUNCA por debajo de media pantalla. Una hoja que
   sube dos dedos parece un error o un aviso del sistema: si algo merece abrirse en una hoja,
   merece ocupar sitio. El cuerpo se estira para llenarla, que si no queda un blanco raro
   entre el texto y el borde. */
/* La copia del día de al lado mientras deslizas. Se coloca a mano, midiendo la hoja de
   verdad (app.js), porque a la hoja la centra un flex y adivinar su sitio con porcentajes
   la deja descuadrada en cuanto cambia el ancho de la pantalla.
   No se toca: es lo que se ve venir, y el día de verdad llega al soltar el dedo. */
.dia-previa {
	position: absolute; margin: 0; pointer-events: none;
	max-width: none; min-height: 0;
}
.sheet-panel--auto { min-height: min(55vh, 55dvh); }
.sheet-panel--auto .sheet-body { flex: 1 1 auto; }

.sheet-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 1rem 1.4rem; display: grid; gap: 0.6rem; align-content: start; overscroll-behavior: contain; touch-action: pan-y; }
.sheet-body > * { min-width: 0; }
/* Una hoja SIN pie termina en su cuerpo, así que el hueco del borde curvo del iPhone lo
   reserva el cuerpo. Con pie lo reserva el pie, y aquí sobraría. */
.sheet-panel > .sheet-body:last-child { padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }

.sheet-footer {
	flex: 0 0 auto; padding: 0.9rem 1.4rem calc(0.9rem + env(safe-area-inset-bottom));
	border-top: 1px solid var(--line); display: flex; justify-content: flex-end; gap: 0.6rem;
	background: var(--surface);
}

.chip-label { margin: 0.2rem 0 0; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text); }
.chip-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; }
/* La difusión y el empujoncito los pone .fila-desliza (bloque "UNA FILA QUE SE DESLIZA"),
   del que esta clase es alias. Aquí había un gradiente escrito a mano, permanente: seguía
   difuminando el borde derecho cuando ya no quedaba nada a la derecha. */
.tag-list--scroll {
	display: flex; gap: 0.3rem; flex-wrap: nowrap;
}
.chip {
	padding: 0.5rem 0.9rem; border-radius: 999px; border: 1px solid var(--line);
	background: var(--surface); font-size: 0.88rem; font-weight: 500; color: var(--text);
	cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
.chip:hover { border-color: var(--accent); }
.chip.is-selected { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }

/* Pestañas de categoría (Gustos) --------------------------------------------------------- */

.tabs::-webkit-scrollbar { display: none; }
/* Alias de .fila-desliza: la difusión ya no se escribe aquí (y era de 3,5rem, distinta de
   los 3,2rem de las otras dos filas — tres copias, tres medidas). */
/* El relleno de "la pestaña elegida" está escrito UNA vez, más abajo: buscar
   "LA OPCIÓN ELEGIDA". Estaba aquí y otras dos veces idéntico. */

/* La foto de un gusto: la portada de la película, el plato, el monumento — o el emoji que le
   toca por su nombre cuando no hay foto. CUADRADA, no redonda: una carátula o un plato
   recortados en círculo se reconocen peor, y aquí lo que importa es identificarlos de un
   vistazo en una lista larga. */
.gusto-emoji {
	flex: 0 0 auto; width: 2.9rem; height: 2.9rem; border-radius: var(--radius-sm);
	display: flex; align-items: center; justify-content: center;
	background: var(--tint); font-size: 1.4rem; line-height: 1;
	overflow: hidden;
}
.gusto-emoji img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* La misma pieza, como botón dentro de la hoja de editar: bastante más grande, que ahí la
   foto es el asunto y no un adorno de la fila. El recorte vive en el span de dentro, NO en
   el botón: con overflow oculto aquí, el lápiz que cuelga de la esquina salía cortado. */
.gusto-emoji--editable {
	position: relative; width: 4.6rem; height: 4.6rem; font-size: 2rem;
	padding: 0; border: 1px solid var(--line); cursor: pointer; overflow: visible;
}
.gusto-emoji--editable > span:first-child {
	width: 100%; height: 100%; border-radius: var(--radius-sm); overflow: hidden;
	display: flex; align-items: center; justify-content: center;
}
.gusto-emoji-lapiz {
	position: absolute; right: -0.35rem; bottom: -0.35rem;
	width: 1.5rem; height: 1.5rem; border-radius: 50%;
	background: var(--accent); color: #FFFFFF; border: 2px solid var(--surface);
	display: flex; align-items: center; justify-content: center;
}

/* Cabecera de Gustos pegada arriba: el título, quién y las categorías se quedan fijos y solo
   corre la lista. El "top" lo pone el JS midiendo la barra superior, que también es sticky y
   cambia de alto entre móvil y escritorio. */
.gustos-sticky {
	position: sticky; top: 0; z-index: var(--z-sticky);
	background: var(--bg, #FAF9F6);
	padding-bottom: 0.5rem; margin-bottom: 0.2rem;
	box-shadow: 0 0.6rem 0.6rem -0.6rem rgba(0, 0, 0, 0.08);
}
/* MIENTRAS SUBE UN VÍDEO. Ocupa el hueco del mensaje que va a llegar, del lado tuyo, con la
   portada ya sacada difuminada debajo: se ve QUÉ está subiendo, no un rectángulo gris.
   Difuminada y a media luz a propósito — tiene que leerse como "todavía no está", no como un
   mensaje enviado. */
.chat-subiendo { position: relative; overflow: hidden; min-width: 9rem; min-height: 9rem; }
.chat-subiendo-portada {
	position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
	filter: blur(6px); opacity: 0.55; transform: scale(1.1);
}
.chat-subiendo-pie {
	position: relative; display: flex; align-items: center; justify-content: center;
	gap: 0.45rem; height: 100%; min-height: 9rem;
	font-size: 0.78rem; color: #FFFFFF; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
.chat-subiendo-giro {
	width: 0.9rem; height: 0.9rem; border-radius: 50%; flex-shrink: 0;
	border: 2px solid rgba(255, 255, 255, 0.45); border-top-color: #FFFFFF;
	animation: chat-subiendo-vuelta 0.8s linear infinite;
}
@keyframes chat-subiendo-vuelta { to { transform: rotate(360deg); } }
/* Quien haya pedido en su móvil que no le muevan las cosas, no se las movemos: el giro se
   queda quieto y el texto sigue diciendo lo mismo. */
@media (prefers-reduced-motion: reduce) {
	.chat-subiendo-giro { animation: none; }
}

/* LA OPCIÓN ELEGIDA — una fila de botones donde uno está marcado (las categorías de
   Gustos, las sub-pestañas de Mi cuenta, la subnav, quién pagó un gasto) se rellena de
   acento SIEMPRE igual. Estaba escrito cuatro veces, una por sitio, y cada copia era una
   ocasión de que un sitio nuevo se quedara sin ella o se pintara distinto. Va al FINAL
   de los estilos de estos botones para ganar por orden, no por especificidad. */
.tab-btn.is-active,
.subnav-tab.is-active,
.subtab-btn.is-active,
.paga-btn.is-active,
.filtro-btn.is-active { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }

/* LECTURAS: una fila es su TÍTULO, con la categoría, de dónde sale y de quién debajo. El
   texto entero se lee al abrirla, en su propio elemento —el único con pre-wrap, la misma
   regla que la burbuja del chat—. */
.lecturas-lista { list-style: none; padding: 0; margin: 1rem 0 0; display: flex; flex-direction: column; gap: 0.5rem; }
.lectura-fila {
	width: 100%; display: flex; align-items: center; gap: 0.6rem; text-align: left;
	padding: 0.9rem 1rem; border-radius: var(--radius-sm); cursor: pointer; font: inherit; color: var(--text);
}
.lectura-titulo { font-weight: 600; overflow-wrap: anywhere; }
.lectura-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.6rem; font-size: 0.78rem; color: var(--muted); }
.lectura-texto { margin: 0; white-space: pre-wrap; line-height: 1.6; overflow-wrap: anywhere; }

/* Campo de "escribir y enviar" sin botón separado al lado — el icono va dentro del
   propio campo, a la derecha, y con Intro (o tocando el icono) se envía. Menos carga
   visual que un botón de color entero junto al campo. */
.enviar-inline { position: relative; }
.enviar-inline input { width: 100%; padding-right: 2.6rem !important; }
.enviar-inline-btn {
	position: absolute !important; right: 0.3rem !important; top: 50% !important; transform: translateY(-50%) !important;
	width: 2rem !important; height: 2rem !important; min-width: 0 !important; margin: 0 !important;
	border-radius: 50% !important; border: none !important; background: var(--accent) !important;
	color: #FFFFFF !important; display: flex !important; align-items: center !important; justify-content: center !important;
	cursor: pointer; padding: 0 !important; font: inherit;
}
/* El botón de enviar solo aparece cuando hay algo que enviar. Con el campo vacío es un
   botón que no hace nada, y además pide que lo pulses: en cuanto escribes la primera letra
   aparece, y desaparece al vaciar. :placeholder-shown es "el campo está vacío" dicho en
   CSS, así que no hace falta JS ninguno ni tocar cada formulario de la app.
   El campo mantiene su hueco a la derecha: si el sitio del botón se recuperara al
   escribir, el texto daría un salto con la primera letra. */
.enviar-inline:has(input:placeholder-shown) .enviar-inline-btn,
.enviar-inline:has(textarea:placeholder-shown) .enviar-inline-btn {
	opacity: 0; pointer-events: none;
}
/* El campo del coach lleva el suyo dentro de un envoltorio, así que la regla de arriba no
   lo alcanza: misma idea, un nivel más adentro. */
.campo-con-enviar:has(input:placeholder-shown) .enviar-inline-btn {
	opacity: 0; pointer-events: none;
}
.enviar-inline-btn { transition: opacity 0.15s ease; }
.tab-panel[hidden] { display: none; }

/* Calendario ---------------------------------------------------------------------------- */

.calweek {
	display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
	font-size: 0.66rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
	color: var(--muted); text-align: center; margin-bottom: 2px;
}
/* El row-gap de 0,45rem que había aquí reservaba a ojo el hueco del disco para TODAS las
   filas del mes, tuvieran reacción o no. Ahora lo reserva la casilla que lo lleva (regla
   "Y LA ESQUINA ES SUYA"), así que la rejilla vuelve a ir apretada. */
.calgrid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
/* La casilla del día. Dos cosas que costaron una captura de Rafa:
   - ALTO MÍNIMO. Estaba a `min-height: 0`, así que la fila medía lo que midiera la casilla
     con más cosas dentro y las demás quedaban aplastadas. Un mes sale entonces con filas de
     alturas distintas —una alta porque alguien puso una foto, la siguiente del alto de un
     número— y eso no se lee como un calendario. 3,4rem es el número, su fila de marcas y el
     aire de los dos; lo que lleve avatares crece por su cuenta.
   - NO RECORTA. Con `overflow: hidden` se comía todo lo que asomara del borde: el disco de
     la reacción, que cuelga medio fuera a propósito, salía cortado por la mitad, y las
     marcas de una casilla estrecha, decapitadas. La fila reserva ese aire con un row-gap
     para que lo que asoma caiga en el hueco y no encima del día de abajo. */
.calcell {
	position: relative; min-height: 3.4rem; padding: 0.25rem 0.3rem 0.2rem; border-radius: var(--radius-sm);
	background: var(--surface); border: 1px solid var(--line);
	display: flex; flex-direction: column; gap: 0.1rem; overflow: visible;
	text-decoration: none; cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
a.calcell:hover { border-color: var(--accent); }
.calcell--empty { background: transparent; border-color: transparent; cursor: default; }
.calcell--today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); animation: calcell-today-pulso 1.4s ease-out 2; }
@keyframes calcell-today-pulso {
	0% { box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
	70% { box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 0.5rem color-mix(in srgb, var(--accent) 0%, transparent); }
	100% { box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}
.calcell--selected { background: var(--accent); border-color: var(--accent); }

/* Día con un plan puesto. */
/* El tinte de la celda entera se ha quitado: con el disco del calendario en la esquina la
   marca ya se ve, y teñir además el fondo dejaba el mes lleno de manchas —tres o cuatro
   celdas de otro color entre las blancas— compitiendo con los avatares y las fotos que van
   DENTRO de la celda. Del plan queda el número en acento y en negrita, que se lee sin
   pintar nada de fondo. */
/* La casilla que estás pulsando se marca SOLO ella, con el aro del acento: al abrirse la
   barra encima, dos casillas resaltadas —la pulsada y la de al lado, que tiene su propio
   borde por llevar plan— hacen dudar de a cuál vas a reaccionar. */
.calcell.is-pressing, .calcell.is-reaccionando {
	box-shadow: 0 0 0 3px var(--accent); border-radius: var(--radius-sm); z-index: 1;
}
.calcell--evento {
	background: var(--surface);
}
.calcell--evento .calcell-num { color: var(--accent-text, var(--accent)); font-weight: 700; }
/* Las marcas del día, EN SU PROPIA FILA. Antes iban en absoluto a la altura del número, y
   ahí competían por el mismo ancho con él: con dos marcas no cabían sin comerse el día.
   Ahora la celda son tres filas — el día arriba, las marcas en medio, los avatares abajo —
   y cada cosa tiene su sitio. Las dos filas de abajo miden lo mismo: los discos crecieron y
   los avatares encogieron hasta encontrarse, para que la celda se lea como una columna
   ordenada y no como tres tamaños distintos apilados.
   Van en un contenedor y no colocadas cada una por su cuenta porque un día puede tener las
   dos, y ahí la segunda se montaba encima de la primera.
   La cámara va ANTES del plan, que es donde el plan estuvo siempre. */
.calcell-marcas {
	display: flex; align-items: center; justify-content: center;
	height: 1.1rem; flex: 0 0 auto;
}
/* Las dos marcas del día —hay un plan, hay fotos— se pintan IGUAL: un disco de color con su
   icono en blanco dentro, el mismo lenguaje que los iconos de la barra de abajo. Antes una
   era un punto pelado y la otra un icono suelto, y no se leían como la misma familia; y el
   punto, sin icono dentro, había que aprendérselo de memoria o mirar la leyenda.
   El aro del color del fondo las despega de la celda y una de otra. */
.calcell-marca {
	width: 1.1rem; height: 1.1rem; border-radius: 50%; flex: 0 0 auto;
	display: flex; align-items: center; justify-content: center;
	line-height: 0; color: #FFFFFF; background: var(--accent);
	box-shadow: 0 0 0 1.5px var(--bg, #FAF9F6);
}
/* Las fotos, en el segundo color de la app: dos discos del mismo tono pegados en la misma
   esquina se leen como una sola marca. */
.calcell-marca--foto { background: var(--warn); }
/* Con las dos a la vez se SOLAPAN, como los avatares de los retos: una al lado de la otra
   no caben en una celda de calendario sin comerse el número del día. */
.calcell-marcas > * + * { margin-left: -0.28rem; }
/* Sobre el día seleccionado, que ya es todo del acento, los discos se invierten: fondo
   claro e icono de color, o se perderían dentro de él. */
.calcell--selected .calcell-marca {
	background: var(--surface); color: var(--accent); box-shadow: none;
}
.calcell--selected .calcell-marca--foto { color: var(--warn); }
/* EL HITO: la chincheta, en el sitio del plan (la plantilla pinta una u otra, nunca las
   dos) y un pelín más grande que las demás marcas — un hito es lo que se busca al hojear
   meses hacia atrás y tiene que cantar entre treinta casillas. Como MarcaDelMes en la app. */
.calcell-marca--hito { width: 1.3rem; height: 1.3rem; }
/* LA CHINCHETA DE UN PLAN QUE SE ESTÁ ESCRIBIENDO: marcarlo como hito es una decisión
   sobre lo que escribes, así que vive en la fila del campo y solo aparece con algo escrito
   (:placeholder-shown = vacío). Marcada, en relleno de acento; sin marcar, en suave. */
.hito-btn {
	flex: 0 0 auto; width: 2rem; height: 2rem; border-radius: 50%; border: none; padding: 0;
	display: flex; align-items: center; justify-content: center; cursor: pointer;
	background: var(--accent-soft); color: var(--accent-text);
}
.hito-btn.is-hito { background: var(--accent); color: var(--accent-contrast); }
form:has(input:placeholder-shown) > .hito-btn { display: none; }
/* La misma chincheta delante del título de un plan que ya es hito. */
.hito-pin { color: var(--accent); flex: 0 0 auto; vertical-align: -1px; }

/* El botón de ayuda que va junto al título de cada pantalla, y la fila que los alinea.
   Discreto a propósito: es para quien no sabe qué es esto, y quien ya lo sabe no tiene que
   verlo cada vez que entra. Alineado por la BASE del título y no por el centro, o en un
   título de dos líneas se queda flotando a media altura. */
.titulo-con-ayuda { display: flex; align-items: baseline; gap: 0.5rem; }
.titulo-con-ayuda > h1 { min-width: 0; }
.ayuda-btn {
	flex: 0 0 auto; width: 1.4rem; height: 1.4rem; border-radius: 50%;
	border: 1.5px solid var(--line); background: none; color: var(--muted);
	font: inherit; font-size: 0.8rem; font-weight: 700; line-height: 1;
	display: flex; align-items: center; justify-content: center; cursor: pointer;
	padding: 0; align-self: center;
}
.ayuda-btn:hover { color: var(--accent-text, var(--accent)); border-color: var(--accent); }
/* El cuerpo de una hoja de ayuda: párrafos con aire y una lista de pasos que se lee de un
   vistazo, en vez de un ladrillo. */
.ayuda-cuerpo p { margin: 0 0 0.7rem; font-size: 0.9rem; line-height: 1.5; }
.ayuda-cuerpo ul { margin: 0 0 0.7rem; padding-left: 1.1rem; display: grid; gap: 0.35rem; }
.ayuda-cuerpo li { font-size: 0.9rem; line-height: 1.45; }
.ayuda-cuerpo strong { color: var(--text); }

/* La leyenda del calendario. Ya no vive desplegada debajo del mes —tres filas fijas que se
   leen una vez en la vida y luego solo cargan la pantalla—: vive dentro de su hoja, y
   debajo del mes queda únicamente el enlace que la abre.
   Una sola columna: en un móvil, dos dejaban los textos partidos en tres líneas. */
.calleyenda {
	list-style: none; margin: 0; padding: 0;
	display: grid; gap: 0.9rem;
	font-size: 0.9rem; color: var(--muted);
}
/* El enlace que la abre: centrado bajo el mes y discreto, como el pie de una tabla. */
.calleyenda-abrir {
	margin: 0.9rem 0 0; text-align: center;
	background: none; border: none; padding: 0.3rem; cursor: pointer;
	font: inherit; font-size: 0.78rem; font-weight: 600; color: var(--muted);
	width: 100%; text-decoration: underline; text-underline-offset: 0.2em;
}
.calleyenda-abrir:hover { color: var(--accent-text, var(--accent)); }
.calleyenda li { display: flex; align-items: center; gap: 0.5rem; }
/* Ancho fijo para la marca: así los textos quedan alineados aunque un avatar sea mucho
   más ancho que el punto. */
.calleyenda-marca {
	flex: 0 0 1.5rem; display: flex; align-items: center; justify-content: center;
}
/* El día seleccionado ya es todo del acento: ahí no hay nada que teñir. */
.calcell--selected.calcell--evento { background: var(--accent); }
.calcell--selected.calcell--evento .calcell-num { color: #FFFFFF; }
.calcell--selected .calcell-num { color: #FFFFFF; }
.calcell--selected .cal-dot { background: rgba(255, 255, 255, 0.35); }
.calcell--selected .cal-dot--yo.is-active, .calcell--selected .cal-dot--pareja.is-active { background: #FFFFFF; }
/* La primera fila de la celda: solo el día, y la más baja de las tres. Con line-height 1 no
   arrastra el hueco de una línea de texto entera, que es lo que hacía que la celda pareciera
   tener el número flotando en una banda vacía. */
.calcell-num { font-size: 0.75rem; font-weight: 600; color: var(--muted); line-height: 1; flex: 0 0 auto; }
.calcell--today .calcell-num { color: var(--accent-text); }
.calcell-event {
	display: block; width: 100%; text-align: left; font: inherit; border: none; cursor: pointer;
	font-size: 0.6rem; line-height: 1.2; padding: 0.1rem 0.25rem; border-radius: 3px;
	background: var(--accent-soft); color: var(--accent-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 40rem) {
	/* En pantalla estrecha la casilla encoge, pero NO hasta cero: sin alto mínimo la fila
	   vuelve a medir lo que mida la casilla más llena, que es de donde venía el mes
	   descuadrado. */
	.calcell { min-height: 3rem; font-size: 0.7rem; }
	.calcell-event { font-size: 0.55rem; }
}
.calcell-dots { display: flex; gap: 0.25rem; margin-top: auto; }
/* Los avatares de quién hizo retos ese día: la TERCERA fila de la celda, centrados y
   SUPERPUESTOS cuando están los dos. Solapados y no uno al lado del otro porque en una celda
   de calendario no cabe: dos de 1.5rem con hueco se salen. El borde del color de cada uno
   los separa igual.
   Dentro de la celda miden 1.2rem —los 1.5rem de siempre se quedan para el ranking, donde
   hay sitio— porque es lo que mide la fila de las marcas: las dos filas de abajo tienen que
   pesar lo mismo, o la celda se lee torcida. */
.calcell-avatares {
	justify-content: center; gap: 0; height: 1.1rem; flex: 0 0 auto;
	/* Sin el margin-top:auto de .calcell-dots: ese auto empujaba los avatares al suelo de
	   la celda y todo el aire sobrante se metía entre ellos y los iconos. Las tres filas van
	   seguidas y lo que sobra queda debajo, no en medio. */
	margin-top: 0;
}
.calcell-avatares .reto-avatar-mini { width: 1.1rem; height: 1.1rem; font-size: 0.5rem; }
.calcell-avatares > * + * { margin-left: -0.4rem; }
/* QUIÉN hizo un reto ese día: su inicial en su color. La cara no vale a este tamaño — a
   catorce píxeles son dos borrones iguales, y lo único que esta marca tiene que contar es si
   fue uno, el otro o los dos. El color va en un `style` inline porque lo elige cada persona
   en su perfil: es un dato, no una clase.
   Sin el solape de las caras: dos discos de color pisándose se leen como uno manchado. */
.calcell-avatares > .cal-inicial + .cal-inicial { margin-left: 0.1rem; }
.cal-inicial {
	display: inline-flex; align-items: center; justify-content: center;
	width: 0.95rem; height: 0.95rem; border-radius: 50%;
	color: #FFFFFF; font-size: 0.6rem; font-weight: 700; line-height: 1;
}
.cal-dot {
	display: inline-block; width: 0.55rem; height: 0.55rem; border-radius: 50%; flex: 0 0 auto;
	background: rgba(24, 22, 15, 0.15); border: none;
}
.cal-dot--yo.is-active { background: var(--dot-color-yo, var(--accent)); }
.cal-dot--pareja.is-active { background: var(--dot-color-pareja, var(--warn)); }

/* Panel de Inicio: la estrella, las cifras y las listas de planes ----------------------- */

.app-dash { max-width: 40rem; padding-block: 2rem; }

/* Cabecera de Inicio: las dos fotos, el lazo que las une, y el tiempo juntos ------------ */

.pareja-hero { text-align: center; padding-top: 0.4rem; }
.pareja-hero-fotos { display: flex; align-items: flex-start; justify-content: center; gap: 0; }
.pareja-hero-avatar { position: relative; flex: 0 0 auto; padding-bottom: 0.6rem; }
.pareja-hero-foto {
	width: 5.5rem; height: 5.5rem; border-radius: 50%; overflow: hidden; flex: 0 0 auto;
	border: 3px solid var(--surface); box-shadow: var(--shadow); background: var(--accent-soft);
	display: flex; align-items: center; justify-content: center;
}
.pareja-hero-foto img { display: block; width: 100%; height: 100%; object-fit: cover; }
.pareja-hero-inicial { font-family: var(--font-display); color: var(--accent-text); --tam: 5.5rem; width: 100%; }
.pareja-hero-lazo { flex: 0 0 auto; margin: 0 -0.4rem; align-self: center; }
.pareja-hero-nombre-tag {
	position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
	background: var(--accent); color: #FFFFFF; font-weight: 600; font-size: 0.72rem;
	padding: 0.15rem 0.55rem; border-radius: 999px; white-space: nowrap; box-shadow: var(--shadow);
}
.pareja-hero-tiempo { margin: 0.6rem 0 0; font-family: var(--font-display); font-size: 1.1rem; color: var(--accent-text); }
.pareja-hero-tiempo--vacio { font-family: var(--font); font-size: 0.85rem; color: var(--muted); }
.pareja-hero-tiempo--vacio a { color: var(--accent-text); }

.spotlight {
	margin-top: 0.4rem; padding: 1.6rem; border-radius: var(--radius);
	background: linear-gradient(135deg, var(--accent) 0%, #8F3A1B 100%); color: #FFFFFF;
	box-shadow: var(--shadow);
}
.spotlight-tag { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.85; }
.spotlight h2 { margin: 0.3rem 0 0.3rem; font-size: 1.5rem; color: #FFFFFF; }
.spotlight p { margin: 0; opacity: 0.92; }
.spotlight--empty { background: var(--surface); border: 1px solid var(--line); color: var(--text); }
.spotlight--empty .spotlight-tag { color: var(--accent-text); opacity: 1; }
.spotlight--empty .actions { margin-top: 0.8rem; }

.dash-stats { display: flex; gap: 1.6rem; margin-top: 1.4rem; }
.dash-stat { display: grid; gap: 0.1rem; }
.dash-stat-num { font-family: var(--font-display); font-size: 1.6rem; }
.dash-stat-label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }

/* 2,2rem entre secciones era demasiado en un móvil: con cuatro o cinco bloques, la pantalla
   se lee como una lista de islas sueltas y obliga a desplazar de más. */
.dash-section { margin-top: 1.5rem; }
.dash-section h3 { font-size: 1.1rem; margin: 0 0 0.7rem; }
/* Título y su acción en la misma fila, con la acción pegada a la derecha. El título puede
   ser largo ("Agradecimientos de hoy de Anca"), así que se le deja partir y el botón no se
   encoge. */
.dash-section-cab {
	display: flex; align-items: baseline; gap: 0.7rem; margin-bottom: 0.7rem;
}
.dash-section-cab h3 { margin: 0; min-width: 0; }
.dash-section-cab .dash-section-accion {
	margin-left: auto; flex-shrink: 0; font-size: 0.85rem; padding: 0.35rem 0.8rem;
}
.dash-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.dash-list li {
	display: flex; justify-content: space-between; align-items: flex-start; gap: 0.8rem;
	padding: 0.7rem 0.9rem; background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm); font-size: 0.92rem; box-shadow: var(--shadow);
}
.dash-list--muted li { opacity: 0.7; background: transparent; box-shadow: none; }
.dash-form { margin-top: 0.8rem; }
.dash-cards {
	display: flex; flex-wrap: nowrap; gap: 0.8rem; margin-top: 0.8rem;
	/* El hueco del disco lo reserva la tarjeta que lo lleva, no la fila entera. */
	padding-bottom: 0.25rem;
}
.dash-card { flex: 0 0 auto; width: 11rem; padding: 1rem 1.1rem; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }

/* LA PORTADA: las tarjetas de sus tiras (planes, gustos, tareas) son .dash-card, y esto es lo
   que cada una pone dentro. Un plan lleva la cara de quien tuvo la idea a la izquierda; un
   HITO se marca con su chincheta y un filo de acento, que es lo que lo distingue de una cena
   cualquiera sin tener que leerlo. */
.plan-card { width: 15rem; display: flex; gap: 0.6rem; align-items: flex-start; align-self: flex-start; text-decoration: none; color: inherit; }
.plan-card--hito { border-color: var(--accent); }
.plan-card-cara {
	flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%; overflow: hidden;
	display: grid; place-items: center; background: var(--tint); color: var(--accent-text, var(--accent));
	font-weight: 700; font-size: var(--txt-s);
}
.plan-card-cara img { width: 100%; height: 100%; object-fit: cover; display: block; }
.plan-card-cuerpo { min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.plan-card-cuando { font-size: var(--txt-xs); font-weight: 600; color: var(--accent-text, var(--accent)); }
.plan-card-titulo { font-size: var(--txt-m); line-height: 1.25; overflow-wrap: anywhere; }
.plan-card-fotos { display: flex; align-items: center; margin-top: 0.1rem; }
.plan-card-demas { margin-left: 0.4rem; font-size: var(--txt-xs); color: var(--muted); }
.plan-card-idea { font-size: var(--txt-xs); color: var(--muted); }
.hito-chip {
	align-self: flex-start; display: inline-flex; align-items: center; gap: 0.25rem;
	padding: 0.1rem 0.5rem; border-radius: 999px; background: var(--tint);
	color: var(--accent-text, var(--accent)); font-size: var(--txt-xs); font-weight: 600;
}
.tira-card { width: 11rem; display: flex; flex-direction: column; gap: 0.3rem; text-decoration: none; color: inherit; }
.tira-card-foto {
	width: 100%; height: 6rem; border-radius: var(--radius-sm); overflow: hidden; background: var(--tint);
	display: grid; place-items: center; font-size: 2rem;
}
.tira-card-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tira-card-titulo {
	font-size: var(--txt-m); line-height: 1.25;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tira-card-sub { font-size: var(--txt-xs); color: var(--muted); }
/* La MUESTRA de una tira vacía: apagada y con su marca, para que se lea como lo que es. */
.tira-card--ejemplo { opacity: 0.85; border-style: dashed; }
.ejemplo-chip {
	align-self: flex-start; padding: 0.1rem 0.5rem; border-radius: 999px; background: var(--tint);
	color: var(--muted); font-size: var(--txt-xs); font-weight: 600;
}
.tarea-cuando { font-size: var(--txt-xs); font-weight: 600; color: var(--muted); }
.tarea-cuando--hoy { color: var(--accent-text, var(--accent)); }
.tarea-cuando--vencida { color: var(--bad); }
.saldo-importe { display: block; font-family: var(--font-display); font-size: 1.35rem; color: var(--accent-text, var(--accent)); }
.saldo-importe--a-favor { color: var(--ok); }
.pasos-lista { display: grid; gap: 0.6rem; }
.pasos-cuenta { font-size: var(--txt-xs); font-weight: 600; color: var(--muted); }
.pasos-promesa { margin: 0.6rem 0 0; font-size: var(--txt-s); color: var(--muted); }

/* LA CELEBRACIÓN: a pantalla completa, en el acento de la marca y no en colores de fiesta
   —sigue siendo la misma app—, con vuestras caras, el número grande y corazones que caen. */
.celebracion {
	position: fixed; inset: 0; z-index: calc(var(--z-visor) + 1); overflow: hidden;
	display: flex; flex-direction: column; align-items: center; justify-content: space-between;
	padding: 2rem 1.4rem calc(1.4rem + env(safe-area-inset-bottom));
	background: linear-gradient(135deg, var(--accent), var(--accent-text, var(--accent)));
	color: #FFFFFF; text-align: center;
}
.celebracion[hidden] { display: none; }
.celebracion-lluvia { position: absolute; inset: 0; pointer-events: none; }
.celebracion-corazon {
	position: absolute; top: -40px; color: rgba(255, 255, 255, 0.35);
	animation-name: celebracion-caer; animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes celebracion-caer {
	from { transform: translateY(0) rotate(var(--giro, 0deg)); }
	to { transform: translateY(calc(100vh + 80px)) rotate(var(--giro, 0deg)); }
}
.celebracion-cuerpo { position: relative; flex: 1 1 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.3rem; max-width: 28rem; }
.celebracion-caras { display: flex; margin-bottom: 1rem; filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.2)); }
.celebracion-cara {
	width: 74px; height: 74px; border-radius: 50%; overflow: hidden; border: 3px solid #FFFFFF;
	background: rgba(255, 255, 255, 0.2); display: grid; place-items: center; font-weight: 700;
}
.celebracion-cara + .celebracion-cara { margin-left: -18px; }
.celebracion-cara img { width: 100%; height: 100%; object-fit: cover; display: block; }
.celebracion-cifra { font-family: var(--font-display); font-size: 6rem; font-weight: 700; line-height: 1; animation: celebracion-crecer 0.5s ease-out; }
@keyframes celebracion-crecer { from { transform: scale(0.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.celebracion-unidad { font-size: var(--txt-l); font-weight: 600; opacity: 0.9; }
.celebracion-titulo { margin: 1rem 0 0; font-size: var(--txt-xl); color: #FFFFFF; }
.celebracion-detalle { margin: 0.3rem 0 0; opacity: 0.9; }
.celebracion-seguir {
	position: relative; width: 100%; max-width: 28rem; padding: 0.85rem; border: none; border-radius: 999px;
	background: #FFFFFF; color: var(--accent-text, var(--accent)); font-weight: 700; font-size: var(--txt-m); cursor: pointer;
}

/* Tarjetas y listas de las pantallas de cliente (fondo claro sobre var(--tint)) --------- */

.card { background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow); }

/* Lista ordenable con flechas (Gustos): top 10 numerado, separador, y el resto debajo. --- */

.rank-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.rank-item {
	display: flex; align-items: center; gap: 0.7rem; padding: 0.6rem 0.7rem 0.6rem 0.9rem;
	background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
	min-width: 0; position: relative;
}
.rank-item--resto { background: transparent; opacity: 0.85; }
.rank-badge {
	flex: 0 0 auto; width: 1.6rem; height: 1.6rem; border-radius: 50%;
	background: var(--accent-soft); color: var(--accent-text); font-weight: 700; font-size: 0.78rem;
	display: flex; align-items: center; justify-content: center;
}
.rank-titulo { flex: 1 1 auto; font-size: 0.95rem; }
.rank-titulo--apagado { color: var(--muted); }
.rank-repeat-icon { color: var(--accent-text); vertical-align: -2px; }
.rank-edit-btn {
	flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
	width: 2rem; height: 2rem; padding: 0; color: var(--muted);
	background: transparent; border: none; border-radius: 50%; cursor: pointer;
}
.rank-edit-btn:hover { background: var(--tint); color: var(--accent-text); }
.rank-divider {
	display: flex; align-items: center; gap: 0.6rem; margin: 0.4rem 0;
	font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted);
}
.rank-divider::before, .rank-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* El campo de fecha (widgets.js) es un <button>, que por defecto del navegador centra su
   texto — y, al ser un grid item de .form, se estira a todo el ancho por el stretch por
   defecto de CSS Grid. El resultado sin esto: fechas centradas en una caja ancha, en vez
   de alineadas a la izquierda como cualquier otro campo del formulario. */
.datefield { width: 100%; justify-content: flex-start; text-align: left; -webkit-appearance: none; appearance: none; }

/* Agradecimientos: pulsación larga sobre el mensaje (estilo WhatsApp) --------------------- */

.agradecimiento-longpress, .gusto-longpress, .retomarca-longpress { transition: transform 0.15s ease, background-color 0.15s ease; border-radius: var(--radius-sm); }
.agradecimiento-longpress.is-pressing, .gusto-longpress.is-pressing, .retomarca-longpress.is-pressing { transform: scale(0.97); background: var(--tint); }
.foto-comentario-editpress { transition: transform 0.15s ease; }
.foto-comentario-editpress.is-pressing { transform: scale(0.97); }
/* En iPhone NO HAY HÁPTICO: WebKit no da el motor de vibración a una web, así que el "el
   gesto ha ido" tiene que entrar por los ojos. Por eso el hundido del chat es más marcado
   que el 0.97 de los demás sitios — aquí es lo único que confirma la pulsación larga. */
.chat-longpress { transition: transform 0.12s ease, filter 0.12s ease; }
/* La burbuja de una entrada necesita la misma transición aunque la clase de "mantenme
   pulsado" esté en su FILA: lo que se encoge es ella. */
.chat-burbuja, .reto-msg-burbuja { transition: transform 0.12s ease, filter 0.12s ease; }
/* La señal de "te estoy oyendo" al mantener pulsado va en la PIEZA, y una burbuja se tiñe
   con brillo, no con fondo: tiene el suyo propio —blanco o acento— y pintarle var(--tint)
   encima le quitaba su color. Los dos nombres de burbuja, porque el marcado de los retos
   todavía escribe el viejo. */
.chat-longpress.is-pressing,
.chat-burbuja.is-pressing, .reto-msg-burbuja.is-pressing { transform: scale(0.93); filter: brightness(0.93); }
/* Y mientras la barra está abierta, el elemento sobre el que se abrió se queda SEÑALADO: con
   seis emojis flotando encima de un hilo, sin esto no se sabe a qué mensaje se está
   reaccionando — y menos si la barra ha tenido que recolocarse para caber. */
.is-reaccionando {
	position: relative; z-index: 2;
	outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--radius-sm);
	box-shadow: 0 10px 28px rgba(24, 22, 15, 0.18);
}
.chat-burbuja.is-reaccionando { border-radius: 1rem; }
/* ---- Piezas compartidas ----------------------------------------------------------------
   Estaban escritas a mano en cada sitio: el badge de reacción 11 veces, el chip 9 y el
   avatar apilado 3. Cambiar el aspecto de cualquiera obligaba a buscarlas todas, y la que
   se olvidaba se quedaba distinta. Aquí una vez, y las variantes solo dicen DÓNDE se
   coloca, no cómo es. */
/* ═══ LA REACCIÓN ════════════════════════════════════════════════════════════════════════
   UNA sola forma de enseñar una reacción en toda la app: disco blanco con el emoji dentro,
   colgando MEDIO FUERA de la esquina de ABAJO A LA DERECHA de lo reaccionado. Da igual qué
   sea lo reaccionado —un mensaje, una foto, un gusto, un día del calendario, una sugerencia—
   quien ve ese disco ahí sabe al instante qué es; en cualquier otro sitio hay que volver a
   averiguarlo.

   ESTO ANTES ERAN SIETE CLASES: --disco, --colgado, --esquina, --fila, .calcell-reaccion,
   .chat-reaccion-badge y .foto-reaccion-badge, y cada pantalla elegía. Poder elegir es
   poder equivocarse, y se equivocaba: en la galería el disco de la foto salía DEBAJO Y A LA
   IZQUIERDA porque --disco no llevaba `position` y los right/bottom escritos a mano en el
   atributo style no colocaban nada; en el chat, a la izquierda en la burbuja de tu pareja.
   Aquí ya no hay nada que elegir, y por eso ya no se puede fallar:

     · los NOMBRES VIEJOS son alias de este mismo bloque — el marcado que quede por ahí, y
       el que copies sin mirar, caen igualmente en el sitio bueno;
     · la COLOCACIÓN va con !important — un style="top:…" copiado de otra pantalla no puede
       volver a moverla (para lo que de verdad no cuelga de nada, ver .visor-reaccion abajo);
     · el PADRE se convierte solo en el marco del disco (la regla :has de aquí abajo), así
       que no hay que acordarse de ponerle position: relative en cada sitio;
     · un disco VACÍO no se ve, se escriba el display que se escriba.

   Lo ÚNICO que un contexto puede cambiar es el TAMAÑO, con --reaccion-tam. Si una pantalla
   nueva parece necesitar otra POSICIÓN, la que está mal es la pantalla, no esta regla. */
/* Los cuatro alias --disco, --colgado, --esquina y --fila se han ido: eran los nombres de
   las siete clases de antes, conservados para que el marcado viejo se llevara los arreglos
   sin tocarlo. Ya no queda marcado viejo — no aparecen en una sola página — así que lo
   único que hacían era sugerir que todavía hay varias maneras de colocar una reacción. */
.reaccion-badge,
.calcell-reaccion, .chat-reaccion-badge, .foto-reaccion-badge {
	position: absolute !important;
	right: calc(var(--reaccion-tam, 1.5rem) * -0.2) !important;
	bottom: calc(var(--reaccion-tam, 1.5rem) * -0.72) !important;
	top: auto !important; left: auto !important; z-index: 2;
	display: flex; align-items: center; justify-content: center;
	min-width: var(--reaccion-tam, 1.5rem); height: var(--reaccion-tam, 1.5rem);
	padding: 0 0.25rem; border-radius: 999px;
	background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
	font-size: calc(var(--reaccion-tam, 1.5rem) * 0.6); line-height: 1;
	transition: transform 0.15s ease;
}
/* ---- Y LA ESQUINA ES SUYA ------------------------------------------------------------
   El disco cuelga por DEBAJO del borde, casi entero fuera (72% de su alto), no metido en
   la esquina. Metido se montaba encima de lo último que hubiera ahí dentro — en un mensaje,
   la hora. La solución NO es mover el disco en el chat: la esquina la reclama la reacción,
   así que es la reacción la que dice quién se aparta y cuánto sitio hace falta. Las tres
   reglas de aquí abajo son ESO, y por eso viven aquí y no repartidas por cada pantalla.

   1) Quien lleva disco RESERVA su hueco debajo. Antes cada sitio se lo apañaba: la fila del
      chat con un margen, la de fotos con un relleno, la rejilla del calendario con otro —
      tres números a ojo, y el que faltaba dejaba el disco cortado o montado encima. */
:has(> .reaccion-badge:not(:empty)),
:has(> .chat-reaccion-badge:not(:empty)), :has(> .foto-reaccion-badge:not(:empty)),
:has(> .calcell-reaccion:not(:empty)) {
	/* 1.1 y no 0.78. El disco cuelga un 72% de su alto, así que 0.78 reservaba SEIS
	   centésimas de holgura: el disco no quedaba cortado, pero llegaba a tocar lo de abajo,
	   y en el chat eso es la burbuja del otro. Una reacción pegada a un mensaje ajeno parece
	   de ese mensaje, y entonces no se sabe a qué se reaccionó, que es lo único que el disco
	   tiene que decir. Ahora sobra un tercio de disco por debajo y la reacción se lee
	   claramente como el final de SU burbuja. */
	margin-bottom: calc(var(--reaccion-tam, 1.5rem) * 1.1);
}
/* 2) Y nada más puede vivir en esa esquina. Lo único que lo intentaba es la hora de un
      mensaje, que va abajo a la derecha: se aparta lo que ocupa el disco, y solo cuando de
      verdad hay uno. Si mañana otra cosa quiere esa esquina, se añade a ESTA línea. */
:has(> .reaccion-badge:not(:empty)) > .chat-hora,
:has(> .chat-reaccion-badge:not(:empty)) > .chat-hora {
	padding-right: calc(var(--reaccion-tam, 1.5rem) * 0.85);
}
/* 3) Con UNA excepción, y va aquí para que siga habiendo un solo sitio: en una REJILLA el
      hueco no puede ir en el margen del hijo. Los hermanos de esa fila se estiran a lo alto
      y el que lleva disco se quedaría más bajo que los demás — una casilla del mes distinta
      de las otras. Ahí lo pone la rejilla, con la misma medida. */
.calcell:has(> .reaccion-badge:not(:empty)), .calcell:has(> .calcell-reaccion:not(:empty)) {
	margin-bottom: 0;
}
.calgrid:has(.reaccion-badge:not(:empty)), .calgrid:has(.calcell-reaccion:not(:empty)) {
	row-gap: calc(var(--reaccion-tam, 1.5rem) * 1.1);
}
/* Un disco sin emoji no es un disco: es un lunar blanco pegado a una esquina. Lleva
   !important porque media app lo enseña y lo esconde con un style="display:…" escrito en
   la plantilla, y ese inline ganaría. Así, "no hay emoji" y "no se ve" son lo mismo y no
   pueden desincronizarse. */
.reaccion-badge:empty, .chat-reaccion-badge:empty,
.foto-reaccion-badge:empty, .calcell-reaccion:empty { display: none !important; }
/* El marco lo pone la propia regla: cualquier cosa que lleve un disco dentro pasa a ser su
   referencia. Sin esto había que acordarse de `position: relative` en cada pantalla, y al
   que se le olvidaba le mandaba el disco a la esquina de otro elemento cualquiera. */
:has(> .reaccion-badge), :has(> .chat-reaccion-badge),
:has(> .foto-reaccion-badge), :has(> .calcell-reaccion) { position: relative; }
/* Una casilla de día es pequeña: el mismo disco en el mismo sitio, más chico. Es la única
   variación permitida, y se pide por tamaño, nunca por posición. */
.calgrid, .calcell, .calcell-num { --reaccion-tam: 1.05rem; }

/* Y lo que NO es esto: el emoji del visor a pantalla completa. Ahí no hay elemento del que
   colgar —la foto ocupa la pantalla entera— así que es un CONTROL del visor, arriba con el
   resto de sus botones y en oscuro sobre la foto. Tiene nombre propio a propósito: si
   llevara .reaccion-badge, la regla de arriba lo mandaría a la esquina de abajo, encima de
   los comentarios. */
.visor-reaccion {
	position: absolute; z-index: 1;
	top: calc(3.6rem + env(safe-area-inset-top)); right: 1rem;
	width: 2rem; height: 2rem; border-radius: 50%;
	background: rgba(0, 0, 0, 0.5); color: #FFFFFF; border: none;
	display: flex; align-items: center; justify-content: center;
	font-size: 1.1rem; line-height: 1;
}
.visor-reaccion:empty { display: none; }

/* Chip de etiqueta: la última vez, una etiqueta propia, de quién sale una sugerencia. */
.tag-chip {
	flex-shrink: 0; font-size: var(--txt-xs); line-height: 1;
	padding: 0.25rem 0.55rem; border-radius: 1rem;
	background: var(--surface-alt, #f0ece6); color: var(--muted, #7a7268);
}

/* Avatares apilados: las fotos de un planazo, de un vistazo y sin abrirlo. */
.fotos-mini-avatar {
	width: 1.6rem; height: 1.6rem; border-radius: 50%; object-fit: cover;
	border: 2px solid var(--surface); margin-left: -0.5rem;
}
/* Icono de reglas junto al título de un reto: discreto, que el título mande. */
.reto-info {
	flex-shrink: 0; width: 1.4rem; height: 1.4rem; padding: 0; border: none; cursor: pointer;
	background: none; color: var(--muted); display: flex; align-items: center; justify-content: center;
}

.fotos-mini-avatar:first-child { margin-left: 0; }

/* La pista de tres meses del calendario. El marco recorta, y dentro los tres meses van en
   fila: solo se ve el del medio hasta que el dedo mueve la pista. */
#calendarioMes { overflow: hidden; }
/* El arrastre horizontal es NUESTRO en cualquier calendario; el vertical, del navegador.
   Sin esto, Safari se queda con el gesto en cuanto se mueve el dedo de lado y cancela el
   nuestro a mitad — por eso deslizar funcionaba en la pantalla de Calendario, que ya lo
   tenía puesto en su pista, y no en el calendario del coach, que no la tiene. */
.calendario { touch-action: pan-y; }
/* La pista arranca YA centrada en el mes de en medio, que es el visible. Sin esto, el primer
   pintado enseña el mes anterior (o los tres, si el contenedor aún no ha recortado) hasta que
   el JS coloca la pista: ese instante es el parpadeo. La colocación de después la sigue
   haciendo el JS; esto solo evita el fotograma feo del principio. */
.calpista { display: flex; will-change: transform; touch-action: pan-y; transform: translateX(-100%); }
.calpista > .calgrid { flex: 0 0 100%; }


/* Pulsación larga sobre una FOTO para reaccionar. En iOS, mantener pulsada una imagen
   arranca un arrastre: la foto "se levanta" (ese achatamiento raro) y el navegador manda
   un pointercancel, que aborta la pulsación larga — por eso la barra no llegaba a abrirse
   nunca. La imagen y los badges dejan de recibir el toque y de poder arrastrarse, así que
   el gesto lo recibe siempre el botón entero y llega a completarse. */
.foto-longpress, .quedadafoto-longpress { transition: transform 0.15s ease; touch-action: pan-x; }

/* La reacción y el "hay comentario" van montados sobre el BORDE de la miniatura, como el
   badge de un agradecimiento — no dentro, tapando la foto. Para eso la miniatura deja de
   recortar (el redondeo pasa a la propia imagen) y la fila reserva un poco de alto abajo,
   que si no su scroll los cortaría. */
/* La reacción y el "hay comentario" van montados sobre el BORDE de la miniatura, como el
   badge de un agradecimiento — no dentro, tapando la foto. Para eso la miniatura deja de
   recortar (el redondeo pasa a la propia imagen) y la fila reserva sitio alrededor, que si
   no su scroll los cortaría. La regla lleva las DOS clases porque .fotos-grid-item, que trae
   overflow:hidden, se declara más abajo y con la misma fuerza le ganaría. */
.fotos-grid-item.foto-longpress, .fotos-grid-item.quedadafoto-longpress { overflow: visible; }
.foto-longpress img, .quedadafoto-longpress img { border-radius: var(--radius-sm); }
/* La reacción de una foto ya no se describe aquí: es EL disco de la app (ver el bloque
   "LA REACCIÓN"). Lo que sí es propio de una foto es el "hay comentario", que va en la
   esquina de ABAJO A LA IZQUIERDA — la de la derecha es de la reacción, siempre, y por eso
   se pueden ver los dos a la vez sin montarse. */
.foto-comentario-icono {
	position: absolute; bottom: -0.5rem; left: -0.3rem;
	width: 1.5rem; height: 1.5rem; border-radius: 50%;
	background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
	align-items: center; justify-content: center; line-height: 1; color: var(--muted);
}

/* El puesto de la foto en vuestro top 20, arriba a la izquierda y con el mismo disco que
   el número de un gusto — dentro de la foto, que las dos esquinas de abajo ya están
   ocupadas por la reacción y el comentario. */
.foto-rango {
	position: absolute; top: 0.4rem; left: 0.4rem;
	width: 1.5rem; height: 1.5rem; border-radius: 50%;
	background: var(--accent); color: #FFFFFF; font-weight: 700; font-size: 0.75rem;
	display: flex; align-items: center; justify-content: center; line-height: 1;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}
.foto-longpress.is-pressing, .quedadafoto-longpress.is-pressing { transform: scale(0.97); }
.foto-longpress img, .quedadafoto-longpress img,
.foto-longpress > span, .quedadafoto-longpress > span {
	pointer-events: none; -webkit-user-drag: none;
	-webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
.fotos-mini-avatar:first-child { margin-left: 0 !important; }
#reactionBar {
	transform: scale(0.85); opacity: 0; pointer-events: none;
	transition: transform 0.16s cubic-bezier(.2, 1.4, .4, 1), opacity 0.12s ease;
}
#reactionBar.is-open { transform: scale(1); opacity: 1; pointer-events: auto; }

/* LA LUPA, hermana de la campanita: mismo sitio, mismo tamaño, mismo trato. Va justo a su
   izquierda, suelta cuando la pantalla no tiene cabecera y dentro de la fila cuando la tiene
   — las dos reglas son las de .campanita, escritas aquí una vez para las dos. */
.buscar-btn {
	position: fixed; z-index: var(--z-flotante);
	top: calc(0.6rem + env(safe-area-inset-top)); right: 3.6rem;
	width: 2.75rem; height: 2.75rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
	color: var(--text); border: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
	background: rgba(250, 249, 246, 0.72);
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.topbar .buscar-btn {
	position: relative; margin-left: auto; flex-shrink: 0;
	top: auto; right: auto;
	width: 2.4rem; height: 2.4rem; background: none; backdrop-filter: none;
}
/* Con las dos dentro de la fila, el "margin-left:auto" lo pone SOLO la primera: si lo
   pusieran las dos, la campanita empujaría a la lupa contra el título. */
.topbar .buscar-btn + .campanita { margin-left: 0; }

/* EL NÚMERO DENTRO DE LA PESTAÑA: cuánto hay de cada cosa, sin salir de la propia pestaña.
   Va en su propia píldora, más pequeña y apagada, para que se lea como un dato de la
   pestaña y no como parte de su nombre. En la seleccionada hereda su color. */
.chip-num {
	margin-left: 0.4rem; padding: 0.05rem 0.4rem; border-radius: 999px;
	background: var(--tint); color: var(--muted);
	font-size: 0.75rem; font-weight: 600; line-height: 1.4;
}
.chip.is-selected .chip-num { background: rgba(255, 255, 255, 0.25); color: inherit; }
.chip-num[hidden] { display: none; }

/* Aquí estaba .buscar-totales, la línea de totales debajo del campo. Los números viven ahora
   DENTRO de su pestaña (.chip-num): es el mismo dato en el sitio donde además sirve para
   entrar. */
/* Avisos: la campanita y su pantalla ------------------------------------------------------ */

/* El punto rojo va sobre el icono, con un borde del color de la barra para que se recorte
   contra ella y no parezca parte del dibujo de la campana. */
/* El globo de mensajes sin leer: ya no es un punto, lleva el NÚMERO dentro. Crece con el
   texto (min-width en vez de width fija) para que "9+" no se salga del disco. */
.bottomnav-punto {
	position: absolute; top: -0.35rem; right: -0.5rem;
	min-width: 1.05rem; height: 1.05rem; padding: 0 0.2rem; border-radius: 999px;
	background: #E5484D; border: 2px solid var(--surface); color: #FFFFFF;
	font-size: 0.62rem; font-weight: 700; line-height: 1;
	display: flex; align-items: center; justify-content: center;
	font-variant-numeric: tabular-nums;
}

/* La campanita suelta, arriba a la derecha y por encima de todo lo demás (incluida la
   cabecera pegajosa de Gustos). Sin fondo: lo que tiene que llamar la atención es el punto
   rojo, no el botón. El área que se toca es mayor que el dibujo, que 23px de glifo son un
   objetivo fallado en un móvil. */
/* La campanita suelta, arriba a la derecha y por encima de todo lo demás (incluida la
   cabecera pegajosa de Gustos). Fondo traslúcido con desenfoque: lo justo para que el glifo
   se lea sobre lo que pase por debajo al hacer scroll, sin convertirse en un botón que compita
   con nada. El área que se toca es mayor que el dibujo, que 23px de glifo son un objetivo
   fallado en un móvil. */
/* La campanita suelta, arriba a la derecha y por encima de todo lo demás (incluida la
   cabecera pegajosa de Gustos). Fondo traslúcido con desenfoque: lo justo para que el glifo
   se lea sobre lo que pase por debajo al hacer scroll, sin convertirse en un botón que compita
   con nada. El área que se toca es mayor que el dibujo, que 23px de glifo son un objetivo
   fallado en un móvil. */
.campanita {
	position: fixed; z-index: var(--z-flotante);
	top: calc(0.6rem + env(safe-area-inset-top)); right: 0.7rem;
	width: 2.75rem; height: 2.75rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
	color: var(--text); text-decoration: none; -webkit-tap-highlight-color: transparent;
	background: rgba(250, 249, 246, 0.72);
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
	border: 1px solid rgba(0, 0, 0, 0.05);
}
.campanita:active { opacity: 0.55; }
/* El punto de "tienes algo sin leer": pegado a la esquina del dibujo de la campana, no a la
   del botón — un punto flotando a un dedo de distancia no se lee como suyo. Más grande y con
   un halo del color, que es lo único de la pantalla que tiene que llamar la atención. */
.campanita-punto {
	position: absolute; top: 0.35rem; right: 0.4rem;
	width: 0.7rem; height: 0.7rem; border-radius: 50%;
	background: #E5484D; border: 2px solid var(--bg, #FAF9F6);
	box-shadow: 0 0 0 3px rgba(229, 72, 77, 0.18);
}
.aviso-grupo {
	font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.09em;
	color: var(--muted); margin: 1.6rem 0 0.6rem;
}
.aviso-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.aviso {
	display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.85rem;
	background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
	text-decoration: none; color: inherit; position: relative;
}
/* Sin leer: fondo tintado y un filo de acento a la izquierda. Dos señales, no una — el color
   solo no lo distingue quien no ve bien los tonos. */
.aviso--nuevo { background: var(--tint); border-color: transparent; box-shadow: inset 3px 0 0 var(--accent); }
.aviso-avatar { position: relative; flex: 0 0 auto; width: 2.5rem; height: 2.5rem; }
.aviso-avatar img {
	width: 100%; height: 100%; border-radius: var(--radius-sm); object-fit: cover; display: block;
	border: 1px solid var(--line);
}
/* Sin foto de la que hablar — un agradecimiento, por ejemplo — el icono del tipo ocupa el
   mismo cuadro, en grande y sobre el tinte: la lista mantiene su ritmo aunque las líneas
   sean de cosas distintas. */
.aviso-generico {
	width: 100%; height: 100%; border-radius: var(--radius-sm); background: var(--tint);
	display: flex; align-items: center; justify-content: center; font-size: 1.2rem; line-height: 1;
}
/* El emoji del tipo, colgado del avatar: de un vistazo se sabe QUÉ pasó sin leer la línea. */
.aviso-icono {
	position: absolute; right: -0.25rem; bottom: -0.25rem;
	width: 1.25rem; height: 1.25rem; border-radius: 50%; font-size: 0.7rem; line-height: 1;
	background: var(--surface); border: 1px solid var(--line);
	display: flex; align-items: center; justify-content: center;
}
.aviso-texto { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.aviso-titulo { font-size: 0.92rem; font-weight: 600; }
/* El cuerpo se corta a dos líneas: un comentario largo no puede empujar el resto de la lista
   fuera de la pantalla. */
.aviso-cuerpo {
	font-size: 0.85rem; color: var(--muted); line-height: 1.35;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.aviso-cuando { font-size: 0.72rem; color: var(--muted); }
.aviso-punto { flex: 0 0 auto; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--accent); }

/* Rejilla de las hasta 20 fotos de la pareja, en Inicio: una fila con scroll ------------- */

/* ---- Visor de fotos a pantalla completa ------------------------------------------------
   Los cuatro visores (top 20, álbum desde Inicio, álbum desde Mi cuenta, fotos de un
   planazo) son la MISMA pieza. Estaba escrita cuatro veces en línea, con doscientos
   caracteres por botón, y por eso una ganaba el corazón de reaccionar y otra no. Aquí una
   sola vez: lo que cambia entre visores son las acciones de abajo, no la caja. */
.visor { position: fixed; inset: 0; z-index: var(--z-barra); background: #000; }
/* La pista del carrusel: tres fotos en fila, con un hueco entre ellas como el de la galería
   del móvil. Se mueve con transform, que es lo único que el navegador anima sin repintar. */
.visor-carrusel {
	position: absolute; inset: 0; display: flex; gap: 1rem;
	touch-action: none; will-change: transform;
}
.visor-carrusel .visor-img { position: static; flex: 0 0 100%; }
/* SOLO LA FOTO QUE SE VE responde al dedo. Las dos vecinas de la pista —la anterior y la
   siguiente, que están ahí montadas para poder deslizar— se apagan: al mantener pulsado, el
   menú de iOS ("Guardar en Fotos", "Copiar") apunta a lo que hay bajo el dedo, y con las tres
   activas podía acabar guardando una que no estabas mirando.
   La visible SÍ conserva el menú del sistema a propósito: guardar una foto en el carrete es
   cosa suya, no nuestra, y lo hace mejor que cualquier botón que pongamos. */
.visor-carrusel .visor-img[aria-hidden="true"] {
	pointer-events: none; -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}

.visor-img {
	position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
	/* El gesto horizontal es NUESTRO (pasar de foto): con el touch-action heredado, iOS lo
	   toma por desplazamiento y cancela el puntero a mitad del arrastre. */
	touch-action: none;
}
.visor-boton {
	position: absolute; z-index: 1; border: none; cursor: pointer;
	background: rgba(0, 0, 0, 0.5); color: #FFFFFF; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
}
/* 2,75rem = 44px: el mínimo con el que un dedo acierta sin pensar. */
.visor-cerrar { top: calc(1rem + env(safe-area-inset-top)); right: 1rem; width: 2.75rem; height: 2.75rem; }
.visor-flecha { top: 50%; transform: translateY(-50%); width: 2.75rem; height: 2.75rem; }
.visor-flecha--anterior { left: 0.6rem; }
.visor-flecha--siguiente { right: 0.6rem; }
/* .visor-reaccion se declara una sola vez, junto al disco de reacción (bloque "LA
   REACCIÓN"): son las dos caras de lo mismo y separarlas es cómo se acaba con dos verdades
   sobre dónde va un emoji. Aquí había una segunda definición, sin marcado que la usara. */
.visor-titulo {
	position: absolute; top: calc(1.6rem + env(safe-area-inset-top)); left: 1rem; margin: 0;
	color: #FFFFFF; font-size: var(--txt-m); font-weight: 600; z-index: 1;
}
.visor-pie {
	position: absolute; left: 0; right: 0; bottom: calc(1.2rem + env(safe-area-inset-bottom));
	display: flex; flex-direction: column; align-items: center; gap: 0.6rem; padding: 0 1rem; z-index: 1;
}
.visor-pie > * { width: 100%; max-width: 30rem; }
/* Cabecera del visor, al estilo de la galería del móvil: volver a la izquierda, la fecha
   centrada, y las acciones que no son de todos los días detrás de los tres puntos. Sobre un
   degradado, no sobre discos: seis botones flotando en negro es ruido, y la foto es lo que
   se ha venido a ver. */
.visor-top {
	position: absolute; top: 0; left: 0; right: 0; z-index: 2;
	display: flex; align-items: center; gap: var(--sp-s);
	padding: calc(0.6rem + env(safe-area-inset-top)) 0.5rem 1.6rem;
	background: linear-gradient(rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0));
}
.visor-fecha {
	flex: 1; min-width: 0; margin: 0; text-align: center;
	color: #FFFFFF; font-size: var(--txt-s); font-weight: 600;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.visor-fecha small { display: block; font-weight: 400; opacity: 0.75; font-size: var(--txt-xs); }

/* Pie: la tira de miniaturas y, debajo, la fila de acciones. Mismo degradado invertido. */
.visor-abajo {
	position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
	padding: 2rem 0 calc(0.5rem + env(safe-area-inset-bottom));
	background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.6));
	display: flex; flex-direction: column; gap: var(--sp-s);
}
.visor-comentarios { padding: 0 1rem; display: flex; flex-direction: column; gap: 0.4rem; align-items: center; }
.visor-comentarios > * { width: 100%; max-width: 30rem; }

/* La tira dice DÓNDE estás dentro del carrete sin tener que pasar fotos para averiguarlo.
   La actual se levanta un poco y pierde el redondeo: se localiza de un vistazo. */
.visor-tira { display: flex; gap: 0.25rem; overflow-x: auto; padding: 0.3rem 1rem; scrollbar-width: none; }
.visor-tira::-webkit-scrollbar { display: none; }
.visor-tira-item {
	flex: 0 0 auto; width: 2.6rem; height: 2.6rem; padding: 0; border: none; cursor: pointer;
	border-radius: 4px; overflow: hidden; background: rgba(255, 255, 255, 0.15);
	opacity: 0.55; transition: opacity 0.15s ease, transform 0.15s ease;
}
.visor-tira-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.visor-tira-item.is-actual { opacity: 1; transform: scaleY(1.15); border-radius: 2px; }

/* La fila de acciones, en una píldora clara como los botones de arriba: la barra entera es
   una sola familia, y sobre una foto clara los iconos blancos sueltos se perdían igual que
   se perdían los de la cabecera. */
.visor-acciones {
	align-self: center; display: flex; align-items: center; gap: 0.3rem;
	padding: 0.25rem 0.5rem; border-radius: 999px;
	background: rgba(250, 249, 246, 0.92); backdrop-filter: blur(10px);
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}
.visor-accion {
	width: 2.75rem; height: 2.75rem; border: none; background: none; cursor: pointer;
	color: var(--text); display: flex; align-items: center; justify-content: center;
	border-radius: 50%; font-size: 1.25rem; line-height: 1;
}
.visor-accion[disabled] { opacity: 0.35; cursor: default; }
/* Quitar es lo único de la fila que no se deshace: va en el rojo de la app, no en el negro
   de las demás, para que el dedo no lo confunda con reaccionar o comentar. */
.visor-accion--peligro { color: var(--bad); }

/* Los dos botones de la cabecera: disco claro traslúcido, como la campanita de la app y
   como los de la galería del móvil. Sobre una foto cualquiera, un icono blanco suelto se
   pierde en cuanto la foto es clara; el disco lo sostiene siempre. */
.visor-top-btn {
	position: static; flex: 0 0 auto;
	width: 2.75rem; height: 2.75rem; border-radius: 50%; border: none; cursor: pointer;
	background: rgba(250, 249, 246, 0.82); backdrop-filter: blur(10px); color: var(--text);
	display: flex; align-items: center; justify-content: center;
}

/* El menú de los tres puntos, con el mismo aspecto que el resto de menús de la app (el de
   una sugerencia en Planazos): panel claro, opciones a lo ancho y alineadas a la izquierda,
   separadas por una línea. */
.visor-menu {
	position: absolute; z-index: 3; top: calc(3.9rem + env(safe-area-inset-top)); right: 0.8rem;
	display: flex; flex-direction: column; min-width: 12rem; overflow: hidden;
	background: var(--surface); border: 1px solid var(--line);
	border-radius: var(--radius-sm); box-shadow: var(--shadow);
}
.visor-menu .button { border-radius: 0; justify-content: flex-start; padding: 0.8rem 1.1rem; }
.visor-menu .button + .button { border-top: 1px solid var(--line); }

.visor-vacio {
	position: absolute; left: 1rem; right: 1rem; bottom: calc(1.6rem + env(safe-area-inset-bottom));
	margin: 0; text-align: center; color: #FFFFFF; font-size: var(--txt-m); z-index: 1;
	background: rgba(0, 0, 0, 0.55); border-radius: var(--radius-sm); padding: 0.6rem 0.8rem;
}

/* La barra de puntos del día: 100% siempre, partida en dos según quién ha puesto cuánto.
   Los colores son los de cada uno (los mismos avatares, el mismo calendario), así que se
   lee sin leyenda. La etiqueta —avatar y número— va DENTRO de su trozo, y se sale a un lado
   cuando el trozo es demasiado estrecho para ella. */
.puntos-fila { display: flex; align-items: center; gap: 0.4rem; margin: 0.45rem 0 0; }
/* La pista y los trozos salen de la barra bicolor compartida (ver "Barra bicolor" arriba).
   Aquí solo queda lo PROPIO de la gruesa: que ocupe el ancho de la fila y que sus trozos
   sepan centrar el avatar y el número que llevan dentro. */
.puntos-barra { flex: 1; min-width: 0; height: 1.7rem; }
.puntos-fuera:empty { display: none; }
.puntos-barra-parte {
	display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.puntos-etiqueta {
	display: flex; align-items: center; gap: 0.25rem;
	font-size: 0.8rem; font-weight: 700; color: #FFFFFF; line-height: 1; white-space: nowrap;
}
/* Fuera de la barra no hay color detrás: el número vuelve al color del texto. */
.puntos-etiqueta--fuera { color: var(--text); }
/* Aro blanco alrededor del avatar: dentro de la barra el borde de cada uno es del mismo
   color que su trozo, así que el avatar se fundía con el fondo y no se veía dónde acababa.
   El blanco lo despega de cualquier color, que es lo que hace el mismo aro en el calendario
   cuando los dos avatares se solapan. */
.puntos-etiqueta .reto-avatar-mini {
	width: 1.25rem; height: 1.25rem; font-size: 0.5rem;
	border: 2px solid #FFFFFF; background: #FFFFFF;
}
.puntos-barra-parte--yo { background: var(--color-yo, var(--accent)); }
.puntos-barra-parte--pareja { background: var(--color-pareja, var(--warn)); }
/* Nadie ha marcado nada todavía: gris a medias. */
.puntos-barra--vacia .puntos-barra-parte { background: var(--line); }
.puntos-barra--vacia .puntos-etiqueta { color: var(--muted); }

/* .calcell-reaccion ya no coloca nada: la casilla del día lleva EL disco de la app, y lo
   único suyo es que es más pequeño (--reaccion-tam en el bloque "LA REACCIÓN"). */
/* La casilla del día necesita ser el marco de su reacción, que cuelga de la esquina. */
.calcell { position: relative; }
/* Aquí vivía la regla que escondía dos emojis cuando había acciones a la vista: en una sola
   fila, seis emojis más tres botones no cabían en un móvil y lo que se salía por la derecha
   era justo la papelera. Con las acciones en su propio piso ya no sobra nada, así que los
   seis emojis se quedan siempre — que eran los que el servidor dice que más usáis. */
.barra-accion--mas { background: var(--surface); color: var(--muted); }
/* Todos los emojis, en rejilla. Grandes: se tocan, no se leen. */
.emojis-rejilla {
	display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.3rem;
}
.emojis-rejilla-btn {
	background: none; border: none; cursor: pointer; padding: 0;
	font-size: 1.6rem; line-height: 1; height: 2.9rem; border-radius: var(--radius-sm);
	display: flex; align-items: center; justify-content: center;
}
.emojis-rejilla-btn:active { background: var(--tint); }

/* La barra de emojis se abre SIEMPRE encima de lo que la abrió: un mensaje del hilo, una
   miniatura, un día del calendario o una foto a pantalla completa. Por eso va en la capa de
   más arriba y no en una intermedia — cualquier otra elección es apostar a que nadie va a
   abrir la barra desde algo que esté por encima de ella, y esa apuesta ya se perdió dos
   veces: primero en Mi cuenta y después en el visor de fotos, donde el corazón se quedaba
   señalado (la barra SÍ se abría) y no se veía nada. */
.barra-flotante {
	position: fixed; z-index: var(--z-toast);
	/* EN COLUMNA: los emojis arriba y las acciones debajo. Una sola fila con todo dentro
	   obligaba a esconder dos emojis para que cupiera la papelera, y dejaba las acciones
	   como iconos pelados que había que adivinar. */
	display: flex; flex-direction: column; align-items: stretch; gap: 0.35rem;
	padding: 0.45rem; background: var(--surface); border: 1px solid var(--line);
	/* Deja de ser una píldora: una píldora es una fila de botones, y esto ya es un menú. */
	border-radius: var(--radius-sm); box-shadow: var(--shadow);
	max-width: min(20rem, calc(100vw - 1.2rem));
}
/* La fila de emojis: sigue siendo una píldora, que es lo que es. */
.barra-emojis {
	display: flex; align-items: center; gap: 0.15rem;
	background: var(--tint); border-radius: 999px; padding: 0.15rem 0.3rem;
}
/* Las acciones, una debajo de otra y CON SU NOMBRE. El icono solo no dice qué hace: la
   papelera se entiende, el "+" no — y ese "+" era guardar en vuestros stickers. */
.barra-acciones { display: flex; flex-direction: column; }
.barra-acciones:empty { display: none; }
.barra-emoji {
	font-size: 1.35rem; line-height: 1; background: none; border: none; cursor: pointer;
	/* 44px de objetivo táctil: con seis emojis pegados, 28px hacía fallar el dedo. */
	min-width: 2.75rem; height: 2.75rem; display: flex; align-items: center; justify-content: center;
}
/* El separador entre los dos pisos: una línea horizontal, no un palito vertical — lo que
   separa ahora son la fila de emojis y la lista de acciones, una encima de otra. */
.barra-separador {
	flex: 0 0 auto; height: 1px; width: auto; background: var(--line); margin: 0.1rem 0.3rem;
}
/* Editar y borrar no son un emoji más: son las dos acciones que CAMBIAN algo, y con el gris
   fino de antes se perdían al lado de seis emojis a todo color. Cada una en su disco —el
   acento para editar, el rojo de la app para borrar—, que además es el lenguaje que ya usan
   los iconos de la barra de abajo. */
/* Una acción es una FILA: icono, nombre y todo el ancho para el dedo. El "···" de los
   emojis es la excepción y sigue siendo redondo — vive dentro de la píldora de arriba. */
.barra-accion {
	display: flex; align-items: center; gap: 0.6rem;
	width: 100%; padding: 0.5rem 0.6rem; border-radius: var(--radius-sm);
	background: none; border: none; cursor: pointer; font: inherit; text-align: left;
	color: var(--accent-text, var(--accent));
}
.barra-accion span { color: var(--text); font-size: 0.9rem; }
.barra-accion svg { flex: 0 0 auto; }
.barra-accion:active { background: var(--tint); }
.barra-accion--mas {
	width: 2.3rem; height: 2.3rem; padding: 0; border-radius: 50%; gap: 0;
	justify-content: center;
}
.barra-accion svg { stroke-width: 2.4; }
/* Borrar, en rojo y ENTERA —icono y nombre—: es la única de la lista que no se deshace, y
   es la última. Las demás se distinguen por lo que dicen, no por el color: una lista donde
   cada fila es de un color no es una lista, es un semáforo. */
.barra-accion--borrar { color: var(--bad, #C0392B); }
.barra-accion--borrar span { color: var(--bad, #C0392B); }

/* Un aviso que está vacío no ocupa sitio. Con margen fijo, un <p> de estado deja un hueco
   permanente donde no hay nada que decir — y ese hueco parece separación entre secciones,
   así que descuadra el ritmo de toda la pantalla.
   :empty solo acierta si de verdad está vacío, y estos se rellenan por JavaScript. */
.status--vacio { margin: 0; }
.status--vacio:not(:empty) { margin-top: 0.4rem; }

/* ═══ UNA FILA QUE SE DESLIZA ═══════════════════════════════════════════════════════════
   Cualquier fila que se recorre en horizontal —las fotos, las sugerencias, las etiquetas,
   las pestañas de Gustos— dice DOS cosas sin que nadie las lea:

   · La DIFUSIÓN del borde por el que hay más: lo que sigue se desvanece en vez de cortarse
     a cuchillo. Un corte limpio parece el final; algo que se difumina parece que continúa.
     Y solo en el lado por el que queda algo — la difusión permanente miente en cuanto has
     llegado al final, y en una fila corta miente desde el principio.
   · Un EMPUJONCITO al aparecer: la fila se asoma un dedo y vuelve. Es la única forma de
     enseñar que una cosa se mueve sin escribir "desliza" al lado.

   Estaba escrito TRES veces —.dash-cards, .tag-list--scroll y .tabs--scrollfade—, cada una
   con su gradiente a mano y su distancia distinta (3,2rem aquí, 3,5rem allá), y las fotos,
   que son la fila más larga de la app, no lo tenían. Ahora es una clase: .fila-desliza, y
   los nombres viejos son alias suyos. Lo de encender la difusión en el lado bueno y dar el
   empujón lo hace montarFilaDesliza() en app.js — la clase sola no sabe cuánto queda.
   Una fila nueva solo tiene que llamarse .fila-desliza; no hay nada que copiar. */
.fila-desliza, .fotos-grid, .dash-cards, .tag-list--scroll, .tabs--scrollfade {
	overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.fila-desliza::-webkit-scrollbar, .fotos-grid::-webkit-scrollbar,
.dash-cards::-webkit-scrollbar, .tag-list--scroll::-webkit-scrollbar,
.tabs--scrollfade::-webkit-scrollbar { display: none; }
/* Queda algo a la DERECHA. */
.hay-mas-derecha:not(.hay-mas-izquierda) {
	-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 3.2rem), transparent 100%);
	mask-image: linear-gradient(to right, #000 calc(100% - 3.2rem), transparent 100%);
}
/* Queda algo a la IZQUIERDA: ya has deslizado y llegaste al final. */
.hay-mas-izquierda:not(.hay-mas-derecha) {
	-webkit-mask-image: linear-gradient(to right, transparent 0, #000 3.2rem);
	mask-image: linear-gradient(to right, transparent 0, #000 3.2rem);
}
/* Queda a los dos lados: estás por el medio. */
.hay-mas-izquierda.hay-mas-derecha {
	-webkit-mask-image: linear-gradient(to right, transparent 0, #000 3.2rem, #000 calc(100% - 3.2rem), transparent 100%);
	mask-image: linear-gradient(to right, transparent 0, #000 3.2rem, #000 calc(100% - 3.2rem), transparent 100%);
}

/* La foto reserva el hueco de su reacción ella sola (regla "Y LA ESQUINA ES SUYA"): aquí
   solo queda el aire mínimo de la fila. El relleno de 0,7rem que había —y su margen
   negativo para compensarlo— reservaban sitio para el disco en TODAS las fotos, tuvieran
   reacción o no, y con un número escrito a ojo. */
.fotos-grid {
	display: flex; flex-wrap: nowrap; gap: 0.9rem; min-width: 0;
	/* Abajo hace falta HUECO DE VERDAD: la reacción cuelga por fuera del borde inferior de
	   la miniatura, y como esta fila se desplaza (overflow), lo que sobresale lo recorta.
	   Con 0,25rem el disco del emoji salía cortado por la mitad. 1,1rem es la mitad del
	   disco más un respiro. */
	padding: 0.2rem 0.5rem 1.1rem;
}

/* En un visor a pantalla completa el gesto horizontal es NUESTRO — pasar de foto —, así que
   se le quita al navegador: con el touch-action heredado, iOS lo interpreta como
   desplazamiento y cancela el puntero a mitad del arrastre. Vive en .visor-img. */
.fotos-grid-item {
	position: relative; flex: 0 0 auto; width: 7.5rem; height: 7.5rem;
	border-radius: var(--radius-sm); overflow: hidden; padding: 0; border: 1px solid var(--line);
	background: var(--surface); cursor: pointer;
}
.fotos-grid-item img { display: block; width: 100%; height: 100%; object-fit: cover; }
.fotos-anadir {
	display: flex; align-items: center; justify-content: center; color: var(--muted);
	transition: border-color 0.15s ease, color 0.15s ease;
}
.fotos-anadir:hover { border-color: var(--accent); color: var(--accent-text); }

/* Avatares de Retos: ranking (grande/pequeño + trofeo) y calendario (mini) --------------- */

.reto-avatar-wrap { position: relative; width: 3.4rem; height: 3.4rem; transition: width 0.15s ease, height 0.15s ease; }
.reto-avatar-wrap--grande { width: 4.6rem; height: 4.6rem; }
.reto-avatar {
	width: 100%; height: 100%; border-radius: 50%; object-fit: cover;
	display: flex; align-items: center; justify-content: center;
	background: var(--surface); border: 2px solid var(--line);
	font-size: 0.72rem; font-weight: 600; color: var(--muted); text-align: center; overflow: hidden;
}
.reto-avatar-trofeo { position: absolute; top: -0.5rem; right: -0.3rem; font-size: 1.3rem; line-height: 1; }
/* LA CARA SIN FOTO: la INICIAL en su círculo, en todas partes igual (Inicio, retos, planes,
   calendario). El marcado lleva el NOMBRE entero —es lo que el servidor manda y lo que lee
   un lector de pantalla— y esta regla enseña solo su primera letra: la plantilla no sabe
   cortar texto, y cortarlo en cada pantalla sería la segunda copia que se queda atrás. Antes
   Inicio pintaba "Prueb" cortado por el borde del círculo.
   `--tam` es el diámetro del círculo; la letra es proporcional. */
.avatar-inicial, .pareja-hero-inicial, .reto-avatar--inicial, .reto-avatar-mini.reto-avatar--inicial {
	display: block; text-align: center; overflow: hidden; white-space: nowrap;
	font-size: 0; line-height: calc(var(--tam, 1.5rem) - 3px);
}
.puntos-etiqueta .reto-avatar--inicial { --tam: 1.25rem; }
.avatar-inicial::first-letter, .pareja-hero-inicial::first-letter, .reto-avatar--inicial::first-letter {
	font-size: calc(var(--tam, 1.5rem) * 0.46); text-transform: uppercase; font-weight: 700;
}
.calcell-avatares .reto-avatar--inicial { --tam: 1.1rem; }
.chat-encuesta-caras .reto-avatar--inicial { --tam: 1.15rem; }
.reto-avatar-mini {
	width: 1.5rem; height: 1.5rem; border-radius: 50%; object-fit: cover; flex-shrink: 0;
	border: 1.5px solid var(--surface); background: var(--surface);
	display: flex; align-items: center; justify-content: center;
	font-size: 0.55rem; font-weight: 600; color: var(--muted); overflow: hidden;
}

/* Burbujas de mensaje tipo WhatsApp, para las entradas de un reto de texto: las tuyas a
   la derecha con el color de acento, las de tu pareja a la izquierda con su avatar — el
   ancho nunca llega a ocupar toda la columna, y la reacción se ancla al borde exterior
   de la burbuja, no de la fila entera. ------------------------------------------------ */

/* Las entradas de un reto usan LA MISMA burbuja que el chat: .reto-msg-fila y
   .reto-msg-burbuja son alias de .chat-fila y .chat-burbuja, declarados junto a ellas.
   Aquí había una segunda familia entera —otro radio, otra letra (0,88 frente a 1rem), un
   pico en la esquina que el chat no tiene y un "lo mío" en acento suave en vez de acento—
   así que la misma pieza se veía de dos maneras según la pantalla. Y cada arreglo había que
   hacerlo dos veces: la burbuja del chat ya lleva el disco de la reacción, la cita, la hora
   y el texto en su caja, y nada de eso llegaba aquí.
   Los nombres viejos se quedan a propósito: el marcado no se toca y el arreglo es el mismo
   día. Cuando alguien pase por esas plantillas, que escriba .chat-burbuja. */

/* Botón de opción de un reto (p. ej. "1L", "30min"): sin esto, marcado y sin marcar se
   veían exactamente igual — de ahí que pareciera que nunca se quedaba marcado. */
.reto-opcion.is-active { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }

/* Fila de solo lectura de tu pareja: mismo formato de botón que el tuyo, pero sin poder
   tocarlo — atenuado si no es su opción marcada, resaltado igual que el tuyo si lo es. */
.reto-opcion--readonly { cursor: default; opacity: 0.45; }
.reto-opcion--readonly.is-active { opacity: 1; background: var(--accent); border-color: var(--accent); color: #FFFFFF; }

/* LA FILA ÚNICA de un reto de opciones (la del día, como en la app): cada opción una vez,
   la tuya rellena en rojo con tu cara, la de tu pareja con borde rojo y su cara, las dos
   caras si coincidís; su cara en gris al final si aún no ha marcado. */
.reto-fila-unica { display: flex; align-items: center; gap: 0.5rem; position: relative; flex-wrap: wrap; }
.reto-fila-unica-opciones { display: flex; flex-wrap: wrap; gap: 0.4rem; flex: 1 1 auto; min-width: 0; }
.reto-fila-unica .reto-opcion {
	position: relative; display: inline-flex; align-items: center; gap: 0.3rem;
	padding: 0.3rem 0.7rem; font-size: 0.8rem; min-height: 2rem;
}
.reto-fila-unica .reto-opcion.reto-op--pareja { border: 2px solid var(--accent); }
.reto-op-caras { display: inline-flex; align-items: center; }
.reto-op-caras:empty { display: none; }
.reto-op-cara {
	width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
	border: 1.5px solid var(--surface); background: var(--accent-soft); color: var(--accent-text);
	--tam: 22px;
}
.reto-op-cara.reto-avatar--inicial { display: inline-block; }
.reto-op-caras .reto-op-cara + .reto-op-cara { margin-left: -6px; }
.reto-cara-pendiente { display: inline-flex; flex-shrink: 0; filter: grayscale(1); opacity: 0.45; }
.reto-fila-puntos-pareja { color: var(--muted); }

/* Borde de cada avatar con el color de perfil de esa persona (--color-yo / --color-pareja,
   fijados una vez en el contenedor de la página) — así cada uno se distingue de un
   vistazo, en el ranking, el calendario y los mensajes. */
.reto-avatar--yo, .reto-avatar-mini--yo { border-color: var(--color-yo, var(--line)); }
.reto-avatar--pareja, .reto-avatar-mini--pareja { border-color: var(--color-pareja, var(--line)); }

/* ---- Modo oscuro: los colores escritos a mano -----------------------------------------
   Los TOKENS se cambian arriba, con el resto de la paleta. Aquí abajo van las superficies
   que llevan su color en crudo, porque el desenfoque necesita un color con alfa y una
   variable con alfa no se puede componer.
   VAN AL FINAL DEL FICHERO A PROPÓSITO: a igual especificidad gana la última regla, y
   puestas arriba —donde parecían ir, junto a la paleta— las pisaba la regla original de cada
   elemento. Eso dejó la barra de abajo en blanco dentro de una app en negro. */
@media (prefers-color-scheme: dark) {
	.topbar { background: rgba(21, 19, 15, 0.82); }
	.bottomnav { background: rgba(31, 28, 23, 0.92); }
	.bottomnav-item.is-active .bottomnav-icon { box-shadow: 0 0 0 3px var(--accent-soft); }
	.campanita { background: rgba(21, 19, 15, 0.72); border-color: rgba(255, 255, 255, 0.08); }
	/* La píldora de acciones del visor: se llama .visor-acciones, no .visor-barra — corregí
	   antes un nombre que no existía y por eso seguía saliendo clara con los iconos blancos
	   encima, o sea invisibles. Los iconos se ponen explícitos y no heredados. */
	.visor-acciones { background: rgba(31, 28, 23, 0.92); }
	.visor-accion { color: #FFFFFF; }
	.visor-cerrar { background: rgba(31, 28, 23, 0.85); color: #FFFFFF; }
	/* El aro blanco de los avatares pasa al de la superficie: un anillo blanco sobre una
	   barra oscura es una marca luminosa alrededor de cada cara. */
	.puntos-etiqueta .reto-avatar-mini { border-color: var(--surface); background: var(--surface); }
	.bottomnav-punto { border-color: var(--surface); }
	/* La cita dentro de un mensaje de tu pareja: sobre burbuja oscura, el tinte claro. */
	.chat-fila:not(.chat-fila--mia) .chat-cita { background: rgba(255, 255, 255, 0.06); }
	/* EL PATRÓN DEL FONDO, en claro sobre oscuro. No basta con subirle la opacidad al
	   negro: sobre un fondo oscuro, negro sobre negro no existe. Es el mismo dibujo con el
	   color cambiado, igual que hace la app con su token del tema. */
	body:has(.topbar), body.chat-hoja > main {
		background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='300' viewBox='0 0 300 300'><g fill='%23ffffff' fill-opacity='0.055' font-family='system-ui,sans-serif' text-anchor='middle'><text x='34' y='38' font-size='19' transform='rotate(-18 34 38)'>&#9829;&#xFE0E;</text><text x='104' y='20' font-size='25' transform='rotate(13 104 20)'>&#9786;&#xFE0E;</text><text x='176' y='52' font-size='17' transform='rotate(-7 176 52)'>&#9834;&#xFE0E;</text><text x='244' y='26' font-size='21' transform='rotate(26 244 26)'>&#9733;&#xFE0E;</text><text x='272' y='96' font-size='23' transform='rotate(-11 272 96)'>&#9788;&#xFE0E;</text><text x='58' y='98' font-size='21' transform='rotate(16 58 98)'>&#9749;&#xFE0E;</text><text x='136' y='116' font-size='25' transform='rotate(-27 136 116)'>&#9992;&#xFE0E;</text><text x='210' y='134' font-size='19' transform='rotate(9 210 134)'>&#10047;&#xFE0E;</text><text x='26' y='156' font-size='23' transform='rotate(-13 26 156)'>&#9729;&#xFE0E;</text><text x='92' y='182' font-size='17' transform='rotate(21 92 182)'>&#10022;&#xFE0E;</text><text x='162' y='200' font-size='21' transform='rotate(-16 162 200)'>&#9790;&#xFE0E;</text><text x='252' y='188' font-size='19' transform='rotate(11 252 188)'>&#9998;&#xFE0E;</text><text x='46' y='244' font-size='23' transform='rotate(15 46 244)'>&#10085;&#xFE0E;</text><text x='118' y='270' font-size='21' transform='rotate(-9 118 270)'>&#9836;&#xFE0E;</text><text x='196' y='256' font-size='15' transform='rotate(19 196 256)'>&#9733;&#xFE0E;</text><text x='266' y='276' font-size='17' transform='rotate(-21 266 276)'>&#9829;&#xFE0E;</text></g></svg>");
	}
}

/* ═══ LA BARRA DE ARRIBA: DOS GRUPOS, COMO EN iOS ══════════════════════════════════════════
   A la IZQUIERDA su cara y el globo del chat (partials/grupopareja.html); a la DERECHA la
   campanita y tu cuenta (partials/campanita.html). Sueltos —Inicio, sin cabecera— cada grupo
   flota en su esquina como una píldora traslúcida; dentro de la cabecera son un elemento más
   de la fila, sin fondo.
   Va AL FINAL a propósito: tiene que ganar a .campanita y .topbar .campanita de arriba, que
   la describían suelta. */
.barra-grupo {
	position: fixed; z-index: var(--z-flotante);
	top: calc(0.6rem + env(safe-area-inset-top));
	display: flex; align-items: center; gap: 0.3rem;
	padding: 0.2rem 0.35rem; border-radius: 999px;
	background: rgba(250, 249, 246, 0.72);
	backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
	border: 1px solid rgba(0, 0, 0, 0.05);
}
.barra-grupo--izq { left: 0.7rem; }
.barra-grupo--der { right: 0.7rem; }
.topbar .barra-grupo {
	position: relative; top: auto; left: auto; right: auto; z-index: auto; flex-shrink: 0;
	padding: 0; background: none; border: none;
	backdrop-filter: none; -webkit-backdrop-filter: none;
}
.topbar .barra-grupo--der { margin-left: auto; }
/* LOS TRES ICONOS DE ARRIBA —globo, campana, persona— SON DE LA MISMA FAMILIA: solo
   contorno, el mismo trazo grueso, el rojo de la marca y el mismo tamaño. El trazo va en
   el CSS y no en cada <svg>: un icono nuevo que se añada aquí sale igual sin acordarse. */
.icono-barra {
	position: relative; flex-shrink: 0;
	display: flex; align-items: center; justify-content: center;
	width: 2.6rem; height: 2.6rem; border-radius: 50%;
	color: var(--accent-text, var(--accent)); text-decoration: none;
	-webkit-tap-highlight-color: transparent;
}
.icono-barra svg { width: 1.75rem; height: 1.75rem; stroke-width: 2.3; fill: none; }
.icono-barra:active { opacity: 0.55; }
.icono-barra[hidden] { display: none; }
.barra-grupo .campanita {
	position: relative; top: auto; right: auto; margin: 0;
	width: 2.6rem; height: 2.6rem;
	background: none; border: none; backdrop-filter: none; -webkit-backdrop-filter: none;
	color: var(--accent-text, var(--accent));
}
.barra-grupo .campanita[hidden] { display: none; }
.barra-grupo .campanita-punto { top: 0.3rem; right: 0.35rem; }
/* El NÚMERO de lo sin leer sobre el globo: el mismo disco que llevaba el icono del chat en
   la barra de abajo, colgando de la esquina del globo. */
.icono-barra .bottomnav-punto { top: 0.05rem; right: -0.05rem; }
.barra-grupo .topbar-pareja .chat-cabecera-foto { width: 2.2rem; height: 2.2rem; }

/* ═══ EL CHAT, UNA HOJA QUE SUBE (chat.html, ChatDeLado en iOS) ═══════════════════════════
   La página entera es la hoja: el asa, el hilo (<main>) y el compositor, sobre un fondo
   oscuro que asoma arriba — lo que dice que es algo abierto ENCIMA, y lo que se toca para
   cerrarla. Sube cuando app.js pone .hoja-lista (el hilo ya está en el último mensaje).
   Se mueven las tres piezas con el mismo transform y nunca el body: el body no se toca
   (ver el teclado en app.js). */
html:has(body.chat-hoja), body.chat-hoja { background: #12100D; }
.hoja-asa {
	flex: 0 0 auto; position: relative; z-index: var(--z-nav);
	display: flex; justify-content: center; align-items: flex-start;
	height: 1.5rem; padding-top: 0.45rem;
	margin-top: calc(env(safe-area-inset-top) + 0.6rem);
	background: var(--bg, #FAF9F6); border-radius: 1.1rem 1.1rem 0 0;
	touch-action: none; cursor: grab; -webkit-tap-highlight-color: transparent;
}
.hoja-asa span {
	width: 2.4rem; height: 0.32rem; border-radius: 999px;
	background: var(--muted); opacity: 0.45;
}
body.chat-hoja > main { background-color: var(--bg, #FAF9F6); background-repeat: repeat; }
/* El pie de la plataforma ("Con la tecnología de…"): en las secciones lo esconde la regla de
   los hermanos de la barra de abajo, pero el chat ya no la lleva y asomaba bajo la hoja. */
body.has-bottomnav .powered-by { display: none; }
/* INICIO, SIN CABECERA: los dos grupos flotan arriba y se montaban sobre vuestras caras. Se
   deja el hueco de la barra encima del contenido. */
body.has-bottomnav:not(:has(.topbar)) > .barra-grupo ~ main { padding-top: calc(3.4rem + env(safe-area-inset-top)); }
body.chat-hoja > .chat-pie { padding-bottom: calc(0.5rem + env(safe-area-inset-bottom)); }
body.chat-hoja > .hoja-asa,
body.chat-hoja > main,
body.chat-hoja > .chat-pie { transition: transform 0.34s cubic-bezier(.2, .9, .3, 1); }
body.chat-hoja:not(.hoja-lista) > .hoja-asa,
body.chat-hoja:not(.hoja-lista) > main,
body.chat-hoja:not(.hoja-lista) > .chat-pie { transform: translateY(100vh); }
@media (prefers-reduced-motion: reduce) {
	body.chat-hoja > .hoja-asa, body.chat-hoja > main, body.chat-hoja > .chat-pie { transition: none; }
}
/* Sin menú de la izquierda en el escritorio: el chat es una hoja por encima de todo, y el
   hueco del menú quedaría vacío. */
@media (min-width: 900px) {
	body.has-bottomnav.chat-hoja { margin-left: 0; }
}

/* ---- EL MAPA (/relaciones/mapa) --------------------------------------------------------
   El mapa ocupa TODO <main>, de la cabecera a la barra de abajo: es la pantalla, no una
   caja dentro de ella. Encima flotan el buscador y las categorías, como en la app. <main>
   no se desplaza aquí: lo que se arrastra es el mapa. */
/* `isolation`: los z-index de Leaflet (400-1000) y del buscador flotante se quedan DENTRO de
   <main>. Sin esto competían con los de toda la página y el buscador salía por encima de una
   hoja abierta — visto en la primera captura. */
body.mapa-pantalla > main { position: relative; overflow: hidden; isolation: isolate; }
.mapa-lienzo { position: absolute; inset: 0; z-index: 0; background: var(--tint); }
/* Leaflet trae su fuente y su fondo; que hable como la app. */
.mapa-lienzo.leaflet-container { font: inherit; }
.mapa-arriba {
	position: absolute; top: var(--sp-s); left: var(--sp-s); right: var(--sp-s); z-index: 500;
	display: flex; flex-direction: column; gap: var(--sp-xs);
	max-width: var(--ancho-app); margin: 0 auto; pointer-events: none;
}
.mapa-arriba > * { pointer-events: auto; }
.mapa-buscar {
	display: flex; align-items: center; gap: var(--sp-xs); height: 2.6rem; padding: 0 0.8rem;
	background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
	box-shadow: var(--shadow); color: var(--muted);
}
.mapa-buscar input {
	flex: 1; min-width: 0; border: none; background: none; outline: none; padding: 0;
	font: inherit; font-size: 1rem; color: var(--text);
}
.mapa-buscar-limpiar { background: none; border: none; padding: 0.2rem; color: var(--muted); cursor: pointer; display: flex; }
.mapa-resultados {
	background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-control);
	box-shadow: var(--shadow); overflow: hidden;
}
.mapa-resultado {
	display: block; width: 100%; text-align: left; padding: 0.55rem 0.9rem; cursor: pointer;
	background: none; border: none; border-bottom: 1px solid var(--line); font: inherit; color: var(--text);
}
.mapa-resultado:last-child { border-bottom: none; }
.mapa-resultado strong { display: block; font-size: 0.92rem; }
.mapa-resultado span { display: block; font-size: 0.78rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mapa-resultados-nada { margin: 0; padding: 0.55rem 0.9rem; font-size: 0.85rem; color: var(--muted); }
.mapa-filtros { display: flex; gap: var(--sp-xs); overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
.mapa-filtros::-webkit-scrollbar { display: none; }
.mapa-filtros .chip { flex: 0 0 auto; padding: 0.3rem 0.7rem; font-size: 0.8rem; box-shadow: var(--shadow); background: var(--surface); }
.mapa-filtros .chip.is-selected { background: var(--accent); }
.mapa-pista {
	position: absolute; left: 50%; bottom: var(--sp-m); transform: translateX(-50%); z-index: 500;
	margin: 0; padding: 0.35rem 0.8rem; border-radius: 999px; white-space: nowrap;
	background: var(--surface); box-shadow: var(--shadow); font-size: 0.78rem; color: var(--muted);
	pointer-events: none;
}
/* LA CHINCHETA: una gota del acento con el icono de su categoría, y la reacción colgando de
   su esquina como en todo lo demás de la app (el disco lo pone ponerReaccion). */
.mapa-pin { background: none; border: none; }
.mapa-pin-gota {
	position: relative; width: 34px; height: 34px; margin: 0 auto;
	border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
	background: var(--accent); border: 2px solid #FFFFFF; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
	display: flex; align-items: center; justify-content: center;
}
.mapa-pin-icono { transform: rotate(45deg); font-size: 15px; line-height: 1; }
.mapa-pin-marco { position: relative; width: 34px; --reaccion-tam: 1.1rem; }
/* El punto nuevo, el que todavía no es un sitio: la misma gota, en hueco. */
.mapa-pin--nuevo .mapa-pin-gota { background: var(--surface); border-color: var(--accent); border-style: dashed; }
/* CASA: la misma gota, más grande, con la casa blanca y un halo — se encuentra sin buscarla
   entre todas las demás (y va encima de ellas: zIndexOffset en app.js). */
.mapa-pin-marco.mapa-pin--casa { width: 46px; }
.mapa-pin--casa .mapa-pin-gota {
	width: 46px; height: 46px; border-width: 3px;
	box-shadow: 0 0 0 4px var(--accent-soft), 0 3px 10px rgba(0, 0, 0, 0.35);
}
.mapa-pin--casa .mapa-pin-icono svg { display: block; width: 22px; height: 22px; }
/* La estrella de favorito en la ficha de un sitio. */
.lugar-favorito {
	flex-shrink: 0; margin-left: auto; background: none; border: none; cursor: pointer;
	padding: 0.2rem 0.3rem; font-size: 1.5rem; line-height: 1; color: var(--muted);
}
.lugar-favorito.is-on { color: var(--accent); }
.mapa-popup-guardar { font: inherit; font-weight: 600; }
/* La ficha de un sitio. */
.lugar-cabecera { display: flex; gap: var(--sp-s); align-items: flex-start; }
.lugar-cabecera-icono {
	flex: 0 0 auto; width: 2.4rem; height: 2.4rem; border-radius: 50%;
	display: flex; align-items: center; justify-content: center; font-size: 1.2rem;
	background: var(--accent-soft);
}
.lugar-nombre { margin: 0; font-family: var(--font-display); font-size: 1.25rem; line-height: 1.25; }
.lugar-categoria { margin: 0; font-size: 0.85rem; font-weight: 600; color: var(--accent-text); }
.lugar-meta { margin: 0; font-size: 0.8rem; color: var(--muted); }
.lugar-descripcion { margin: 0; white-space: pre-wrap; }
.lugar-acciones { display: flex; flex-wrap: wrap; gap: var(--sp-xs); }
.lugar-reacciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); }
.lugar-reacciones .barra-emoji { border-radius: 50%; border: 1.5px solid transparent; }
.lugar-reacciones .barra-emoji.is-selected { background: var(--accent-soft); border-color: var(--accent); }
.lugar-reaccion-suya { margin: 0; font-size: 0.82rem; color: var(--muted); }
.lugar-comentarios { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.lugar-comentario-borrar {
	flex: 0 0 auto; background: none; border: none; padding: 0.2rem; cursor: pointer; color: var(--muted);
	align-self: center;
}

/* ---- LOS ENLACES: sitio del mapa ↔ foto ↔ plan -----------------------------------------
   Una foto, un plan y un sitio se señalan unos a otros, y desde cualquiera se viaja a los
   otros dos. El chip es UNA pieza (chipDeEnlace en app.js) en el visor, en el popup de un
   plan y donde haga falta: lleno es un enlace que lleva a lo enlazado, con cambiar y quitar
   al lado; vacío, un "Añadir" en discontinuo. */
.enlaces-fila { display: flex; flex-wrap: wrap; gap: var(--sp-xs); }
.enlace-chip {
	display: inline-flex; align-items: center; max-width: 100%; min-width: 0;
	border-radius: 999px; background: var(--surface); border: 1px solid var(--line);
	font: inherit; font-size: 0.85rem; color: var(--text);
}
.enlace-chip-ir {
	display: block; min-width: 0; padding: 0.35rem 0.3rem 0.35rem 0.8rem;
	color: inherit; font-weight: 600; text-decoration: none;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.enlace-chip-btn {
	flex: 0 0 auto; border: none; background: none; cursor: pointer; color: var(--muted);
	padding: 0.35rem 0.4rem; display: flex; align-items: center;
}
.enlace-chip-btn:last-child { padding-right: 0.65rem; }
.enlace-chip--vacio { padding: 0.35rem 0.85rem; cursor: pointer; border-style: dashed; color: var(--muted); font-weight: 500; }
/* En el visor, sobre la foto: la misma píldora clara que la fila de acciones. */
.visor-enlaces { justify-content: center; padding: 0 1rem; }
.visor-enlaces .enlace-chip { background: rgba(250, 249, 246, 0.92); border-color: transparent; color: #2A2622; }
.visor-enlaces .enlace-chip--vacio { background: rgba(250, 249, 246, 0.7); border-color: rgba(42, 38, 34, 0.35); }
.visor-enlaces .enlace-chip-btn { color: #6B645C; }
/* La hoja de elegir sale ENCIMA del visor: se abre desde él. */
.sheet-overlay--encima { z-index: var(--z-aviso); }
.enlaces-hoja-mes { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-s); }
.enlaces-hoja-mes strong { text-transform: capitalize; }
.enlaces-hoja-mes button { border: 1px solid var(--line); background: var(--surface); color: var(--text); border-radius: 50%; width: 2.2rem; height: 2.2rem; cursor: pointer; font: inherit; }
.enlaces-hoja-seccion { margin: 0.4rem 0 0; }
/* Los planes de un sitio, en su ficha: cada uno lleva a su día. */
.lugar-planes { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.lugar-plan { display: flex; align-items: center; gap: var(--sp-xs); border: 1px solid var(--line); border-radius: var(--radius-control); background: var(--surface); }
.lugar-plan a { flex: 1; min-width: 0; padding: 0.5rem 0.8rem; color: var(--text); text-decoration: none; }
.lugar-plan a strong { display: block; font-size: 0.92rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lugar-plan a span { display: block; font-size: 0.78rem; color: var(--muted); }

/* BUSCAR, la primera fila de Mi cuenta: una fila que se toca, con su lupa del rojo de la
   marca y la flecha de "esto abre algo". */
.fila-buscar {
	display: flex; align-items: center; gap: 0.75rem; width: 100%;
	margin-top: 0.6rem; padding: 0.85rem 1rem;
	background: var(--surface); color: var(--text);
	border: 1px solid var(--line); border-radius: var(--radius-sm);
	font: inherit; font-weight: 600; text-align: left; cursor: pointer;
}
.fila-buscar > :first-child { color: var(--accent-text, var(--accent)); flex-shrink: 0; }
.fila-buscar > span { flex: 1; }
.fila-buscar-flecha { color: var(--muted); flex-shrink: 0; }
.fila-buscar:active { opacity: 0.7; }

@media (prefers-color-scheme: dark) {
	.barra-grupo { background: rgba(21, 19, 15, 0.72); border-color: rgba(255, 255, 255, 0.08); }
	html:has(body.chat-hoja), body.chat-hoja { background: #000000; }
}

/* ═══ LA BURBUJA DE LO TUYO: ROSA EMPOLVADO (como la app, 2026-09-30) ════════════════════
   Era el acento lleno con letra blanca, y una conversación entera en ese rojo cansaba la
   vista. El rojo fuerte queda para lo que se toca. Los mismos valores que `Tema.burbujaMia`
   en iOS; si no coinciden, el que está mal es este. Todo lo que iba "en blanco sobre rojo"
   dentro de tu burbuja (la hora, la nota de voz, la cita) pasa a tinta sobre rosa. */
:root { --burbuja-mia: #F4DAD7; --sobre-burbuja-mia: #2B1A19; --sobre-burbuja-mia-apagado: #9C4A45; }
.chat-burbuja--mia, .reto-msg-burbuja--mia {
	background: var(--burbuja-mia); border-color: var(--burbuja-mia); color: var(--sobre-burbuja-mia);
}
.chat-fila--mia .chat-burbuja:not(.chat-burbuja--emoji):not(.chat-burbuja--sticker) .chat-hora { color: var(--sobre-burbuja-mia-apagado); }
.chat-fila--mia .chat-audio-play { background: var(--accent); color: #FFFFFF; }
.chat-fila--mia .chat-audio-onda i { background: color-mix(in srgb, var(--sobre-burbuja-mia) 22%, transparent); }
.chat-fila--mia .chat-audio-onda i.is-oido { background: var(--accent); }
.chat-fila--mia .chat-cita { background: rgba(255, 255, 255, 0.55); border-left-color: var(--accent); }
.chat-fila--mia .chat-encuesta-opcion { background: rgba(255, 255, 255, 0.7); }
@media (prefers-color-scheme: dark) {
	:root { --burbuja-mia: #4A2F2D; --sobre-burbuja-mia: #F3E6E4; --sobre-burbuja-mia-apagado: #D9A7A3; }
	.chat-fila--mia .chat-cita { background: rgba(255, 255, 255, 0.08); }
	.chat-fila--mia .chat-encuesta-opcion { background: rgba(255, 255, 255, 0.08); }
}

/* ═══ MIVIDA EN EL ORDENADOR (≥1100px) ═══════════════════════════════════════════════════
   Una app de escritorio y no un móvil estirado: la columna de la izquierda con TODAS las
   secciones agrupadas, la cabecera de cada pantalla con su título grande, el contenido en
   rejilla, el día del calendario como PANEL al lado del mes, y (≥1400px) el chat fijo a la
   derecha, como un cliente de mensajería de escritorio.
   TODO va dentro de estas medias: el móvil no cambia. Lo que solo existe en la columna
   (la marca, los títulos de grupo) lleva `bottomnav-solo-escritorio` y fuera no se pinta. */
.bottomnav-solo-escritorio { display: none; }
.panel-chat { display: none; }

@media (min-width: 900px) {
	/* Inicio no lleva cabecera y su grupo de la izquierda flota: sin esto se montaba
	   encima de la columna del menú. */
	body.has-bottomnav > .barra-grupo--izq { left: calc(var(--ancho-menu) + 0.9rem); }
}

@media (min-width: 1100px) {
	:root { --ancho-menu: 15.5rem; --ancho-module: 72rem; --ancho-dia: 30rem; }

	/* ── LA COLUMNA ─────────────────────────────────────────────────────────────────── */
	body.has-bottomnav > .bottomnav {
		background: var(--surface); box-shadow: none; gap: 0.1rem;
		padding: 1rem 0.75rem calc(1rem + env(safe-area-inset-bottom));
	}
	body.has-bottomnav > .bottomnav > * { order: var(--orden, 50); }
	/* El orden de la columna, por grupos. El marcado sigue en el orden del móvil. */
	body.has-bottomnav > .bottomnav .bottomnav-item[href="/agradecimientos"] { order: 2; }
	body.has-bottomnav > .bottomnav .bottomnav-item[href="/analisis"] { order: 4; }
	body.has-bottomnav > .bottomnav .bottomnav-item[href="/mapa"] { order: 13; }
	body.has-bottomnav > .bottomnav .bottomnav-item[href="/tareas"] { order: 21; }
	body.has-bottomnav > .bottomnav .bottomnav-item[href="/gastos"] { order: 22; }
	body.has-bottomnav > .bottomnav .bottomnav-item[href="/cuenta"] { order: 31; }
	body.has-bottomnav > .bottomnav .bottomnav-solo-escritorio { display: flex; }
	.bottomnav-marca {
		align-items: center; gap: 0.65rem; padding: 0.3rem 0.7rem 1.1rem;
		font-family: var(--font-display); font-weight: 700; font-size: 1.2rem;
		color: var(--text); text-decoration: none;
	}
	.bottomnav-marca svg { width: 2rem; height: 2rem; flex-shrink: 0; }
	body.has-bottomnav > .bottomnav .bottomnav-grupo {
		display: block; margin: 1.1rem 0 0.35rem; padding: 0 0.75rem;
		font-size: var(--txt-xs); font-weight: 700; letter-spacing: 0.07em;
		text-transform: uppercase; color: var(--muted);
	}
	/* Las filas: sin el disco rojo de cada icono — en una columna de catorce, catorce
	   discos del acento gritan todos a la vez y ninguno dice dónde estás. El acento se
	   queda para la fila activa. */
	body.has-bottomnav > .bottomnav .bottomnav-item {
		gap: 0.65rem; padding: 0.42rem 0.7rem; border-radius: 0.7rem;
		font-size: 0.9rem; font-weight: 500; color: var(--text);
		transition: background 0.12s ease, color 0.12s ease;
	}
	body.has-bottomnav > .bottomnav .bottomnav-icon {
		width: 1.6rem; height: 1.6rem; background: none; box-shadow: none !important;
		color: var(--accent-text);
	}
	body.has-bottomnav > .bottomnav .bottomnav-icon svg { width: 1.2rem; height: 1.2rem; stroke: currentColor; stroke-width: 1.9; }
	body.has-bottomnav > .bottomnav .bottomnav-item:hover { background: var(--tint); color: var(--text); }
	body.has-bottomnav > .bottomnav .bottomnav-item.is-active { background: var(--accent-soft); color: var(--accent-text); font-weight: 650; }
	body.has-bottomnav > .bottomnav .bottomnav-item.is-active .bottomnav-icon { color: var(--accent-text); }
	/* Avisos y Mi cuenta, abajo del todo: son de la persona, no secciones. */
	body.has-bottomnav > .bottomnav .bottomnav-item--abajo { margin-top: auto; }
	body.has-bottomnav > .bottomnav .bottomnav-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

	/* ── LA CABECERA DE CADA PANTALLA ───────────────────────────────────────────────── */
	.topbar { padding: 0.85rem 2rem; gap: 0.9rem; }
	.topbar-titulo { font-family: var(--font-display); font-size: 1.55rem; letter-spacing: -0.01em; }

	/* ── EL CONTENIDO ───────────────────────────────────────────────────────────────── */
	body.has-bottomnav:not(.chat-hoja) > main > .band > .wrap,
	body.has-bottomnav:not(.chat-hoja) > main > .wrap { padding-left: 2rem; padding-right: 2rem; }
	/* INICIO EN DOS COLUMNAS: vuestras caras y lo que se desliza a lo ancho arriba, y las
	   secciones de dos en dos debajo. Una sola columna en una pantalla de 1440 era una tira
	   de tarjetas con media pantalla vacía a cada lado. */
	body.has-bottomnav:not(.chat-hoja) .module-dash {
		display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		column-gap: 2.2rem; align-items: start;
	}
	body.has-bottomnav:not(.chat-hoja) .module-dash > * { grid-column: 1 / -1; }
	body.has-bottomnav:not(.chat-hoja) .module-dash > .dash-section { grid-column: auto; }
	body.has-bottomnav:not(.chat-hoja) .module-dash > .dash-section:has(.fotos-grid) { grid-column: 1 / -1; }
	/* Las tarjetas se ordenan en filas en vez de desplazarse de lado: con ratón, un
	   carrusel sin barra es contenido escondido. */
	body.has-bottomnav:not(.chat-hoja) .dash-cards { flex-wrap: wrap; overflow: visible; }
	.dash-card { transition: transform 0.15s ease, box-shadow 0.15s ease; }
	.dash-card:hover { transform: translateY(-2px); box-shadow: 0 2px 4px rgba(24, 22, 15, 0.05), 0 16px 32px -12px rgba(24, 22, 15, 0.22); }
	.card { transition: box-shadow 0.15s ease; }
	a.card:hover, button.card:hover { box-shadow: 0 2px 4px rgba(24, 22, 15, 0.05), 0 16px 32px -12px rgba(24, 22, 15, 0.22); }
	.calcell { transition: border-color 0.12s ease, box-shadow 0.12s ease; }
	.calcell:not(.calcell--empty):hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
	:where(a, button, [role="button"], input, textarea, select):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

	/* ── EL DÍA, UN PANEL AL LADO DEL MES ───────────────────────────────────────────── */
	/* En el móvil el día baja y tapa el mes; aquí se queda a la derecha y el mes sigue a la
	   vista: tocar otro día cambia el panel sin cerrar nada. Sin velo oscuro: no hay nada
	   detrás que haya que apagar. */
	body.has-bottomnav #diaDetalleSheet:not([hidden]) {
		position: fixed; top: 0; bottom: 0; left: auto; right: 0; width: var(--ancho-dia);
		background: none; z-index: var(--z-flotante); display: block;
	}
	body.has-bottomnav #diaDetalleSheet > .sheet-panel {
		position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none;
		transform: none; border-radius: 0; border-left: 1px solid var(--line);
		box-shadow: -10px 0 32px -12px rgba(24, 22, 15, 0.18);
	}
	body.has-bottomnav #diaDetalleSheet > .sheet-panel::before { display: none; }
	body.has-bottomnav:has(#diaDetalleSheet:not([hidden])) > main,
	body.has-bottomnav:has(#diaDetalleSheet:not([hidden])) > .topbar { margin-right: var(--ancho-dia); }
	/* La columna se queda: el día ya no tapa la pantalla. */
	body.has-bottomnav.hoja-abierta:has(#diaDetalleSheet:not([hidden])) > .bottomnav { display: flex; }
	body.has-bottomnav.hoja-abierta:has(#diaDetalleSheet:not([hidden])) .topbar { z-index: var(--z-nav); }
}

/* ── EL CHAT, FIJO A LA DERECHA (≥1400px) ───────────────────────────────────────────────
   Es la MISMA página del chat (chat.html) dentro de un marco: el hilo, el cifrado, las
   notas de voz y el sondeo son los de siempre y no hay un segundo chat que mantener. Se
   abre y se cierra con el globo de arriba o con "Chat" en la columna, y se recuerda. */
/* DESDE EL CORTE DE ESCRITORIO (1100px, el de la columna), no desde 1400 (2026-10-01): la app
   instalada en el ordenador abre una ventana más estrecha que la pantalla, y entre 1100 y 1400
   el "Chat" de la columna llevaba a /chat a pantalla completa. Ahí el panel es más estrecho. */
@media (min-width: 1100px) and (max-width: 1399px) {
	:root { --ancho-chat: 22rem; }
}
@media (min-width: 1400px) {
	/* 27,5rem: un 10 % más que los 25 de antes (Rafa, 2026-10-01: "el chat hazlo más ancho"). */
	:root { --ancho-chat: 27.5rem; }
}
@media (min-width: 1100px) {
	body.con-panel-chat { margin-right: var(--ancho-chat); }
	body.con-panel-chat > .panel-chat:not([hidden]) {
		display: flex; flex-direction: column;
		position: fixed; top: 0; right: 0; bottom: 0; width: var(--ancho-chat);
		z-index: var(--z-nav); background: var(--bg);
		border-left: 1px solid var(--line); box-shadow: -10px 0 32px -16px rgba(24, 22, 15, 0.16);
	}
	.panel-chat-cab {
		display: flex; align-items: center; gap: 0.6rem; padding: 0.75rem 0.9rem 0.75rem 1.1rem;
		border-bottom: 1px solid var(--line); background: var(--surface);
	}
	.panel-chat-cab img { width: 2.1rem; height: 2.1rem; border-radius: 50%; object-fit: cover; }
	.panel-chat-cab strong { flex: 1; min-width: 0; font-family: var(--font-display); font-size: 1.05rem; }
	.panel-chat-cerrar {
		background: none; border: none; cursor: pointer; color: var(--muted);
		width: 2rem; height: 2rem; border-radius: 50%; display: flex; align-items: center; justify-content: center;
	}
	.panel-chat-cerrar:hover { background: var(--tint); color: var(--text); }
	.panel-chat iframe { flex: 1; width: 100%; border: 0; background: var(--bg); }
	body.con-panel-chat #diaDetalleSheet:not([hidden]) { right: var(--ancho-chat); }
	body.con-panel-chat > .barra-grupo--der { right: calc(var(--ancho-chat) + 0.9rem); }
	/* El globo del chat, encendido mientras el panel está abierto. */
	body.con-panel-chat #botonChat { background: var(--accent-soft); }
	body.con-panel-chat > .bottomnav #navChat { background: var(--accent-soft); color: var(--accent-text); }
}
/* DÍA Y CHAT A LA VEZ, en una pantalla que no da para tres columnas: el día ocupa el sitio
   del chat mientras está abierto. Con los dos, el mes se quedaba en cinco columnas cortadas. */
@media (min-width: 1100px) and (max-width: 1799px) {
	body.con-panel-chat:has(#diaDetalleSheet:not([hidden])) > .panel-chat { display: none !important; }
	body.con-panel-chat:has(#diaDetalleSheet:not([hidden])) { margin-right: 0; }
	body.con-panel-chat #diaDetalleSheet:not([hidden]) { right: 0; }
}
/* El chat DENTRO del panel: sin asa, sin velo oscuro y sin la animación de subir — ya está
   donde tiene que estar. */
html:has(body.chat-en-panel), body.chat-en-panel { background: var(--bg) !important; }
body.chat-en-panel > .hoja-asa { display: none; }
body.chat-en-panel > main, body.chat-en-panel > .chat-pie { transform: none !important; transition: none !important; }
body.chat-en-panel > main { border-radius: 0; }

/* ═══ SOLTAR FOTOS DESDE EL ORDENADOR ════════════════════════════════════════════════════
   La capa que dice dónde va a caer lo que se arrastra. Encima de todo y sin recoger el
   ratón: los eventos de arrastre los escucha el documento, y una capa que los atrapara
   se comería el `drop`. */
.capa-soltar {
	position: fixed; inset: 0; z-index: var(--z-aviso);
	display: flex; align-items: center; justify-content: center;
	background: color-mix(in srgb, var(--bg) 70%, transparent);
	backdrop-filter: blur(3px); pointer-events: none;
}
.capa-soltar[hidden] { display: none; }
.capa-soltar-caja {
	display: flex; flex-direction: column; align-items: center; gap: 0.7rem;
	padding: 2rem 2.6rem; border-radius: var(--radius);
	border: 2px dashed var(--accent); background: var(--surface); color: var(--accent-text);
	font-weight: 600; box-shadow: var(--shadow);
}

/* Una fila del menú escondida con `hidden` se queda escondida: las reglas de la columna la
   ponen en flex, y a igual o más peso eso pisaría al atributo. */
.bottomnav-item[hidden] { display: none !important; }
/* Las ofertas del pie de la columna (activar avisos, instalar), en el color del acento:
   son algo que hacer, no un sitio al que ir. */
@media (min-width: 1100px) {
	body.has-bottomnav > .bottomnav .bottomnav-item--oferta { color: var(--accent-text); font-size: 0.82rem; }
	body.has-bottomnav > .bottomnav .bottomnav-item--oferta .bottomnav-icon { color: var(--accent-text); }
	/* Instalada, la ventana ya no tiene la barra del navegador encima: la columna empieza
	   pegada al borde y la marca se queda con un poco más de aire arriba. */
	body.app-instalada.has-bottomnav > .bottomnav { padding-top: 1.4rem; }
}
/* La tarjeta a la que se llega desde "Avisos en este ordenador", marcada un momento. */
.tarjeta-resaltada { box-shadow: 0 0 0 3px var(--accent), var(--shadow) !important; transition: box-shadow 0.3s ease; }

/* ═══ PULIDO DE ESCRITORIO: QUITAR LO QUE DELATA UN MÓVIL ESTIRADO ════════════════════════
   Pantalla ancha Y ratón: la MISMA consulta que esEscritorio() en app.js (una tableta
   apaisada es ancha pero se usa con el dedo, y ahí los gestos de móvil son los buenos).
   Criterio de app de escritorio: nada se arrastra con el ratón, las hojas son diálogos
   centrados, las filas que se deslizaban son rejillas que se ven enteras, el menú de
   "mantener pulsado" es el clic derecho y lo que se clica lo dice el cursor.
   Todo aquí dentro: el móvil no cambia. */
.chat-responder-rapido { display: none; }

@media (min-width: 1100px) and (hover: hover) and (pointer: fine) {
	/* DENSIDAD: 17px era la letra de un iPhone. En un monitor, a un palmo más de distancia
	   y con ratón, 16px es lo que usa cualquier app de escritorio; como todo va en rem,
	   baja todo a la vez y en proporción. */
	html { font-size: 16px; }

	/* ── LAS HOJAS SON DIÁLOGOS ─────────────────────────────────────────────────────────
	   Una hoja que sube desde abajo es un gesto de pulgar. Aquí: centrada, con su ancho,
	   bordes redondos por los cuatro lados, sin asa (no se arrastra: se cierra con su X,
	   con Esc o con un clic fuera) y con la altura de lo que lleva dentro. El día del
	   calendario NO: ese es el panel de la derecha (bloque "MIVIDA EN EL ORDENADOR"). */
	.sheet-overlay:not(#diaDetalleSheet) { align-items: center; padding: 4vh 1.5rem; background: rgba(12, 10, 6, 0.42); }
	.sheet-overlay:not(#diaDetalleSheet) > .sheet-panel {
		max-width: 38rem; height: auto; max-height: min(86vh, 56rem);
		border-radius: var(--radius);
		box-shadow: 0 24px 60px -20px rgba(24, 22, 15, 0.35), 0 2px 8px rgba(24, 22, 15, 0.08);
	}
	.sheet-overlay .sheet-panel::before, .sheet-overlay .sheet-header::before { display: none; }
	/* EL CHAT ABIERTO COMO PÁGINA (/chat, sin el panel) tampoco es una hoja: sin asa, sin la
	   franja negra de arriba y sin subir; ocupa su sitio como cualquier pantalla. */
	body.chat-hoja:not(.chat-en-panel) > .hoja-asa { display: none; }
	html:has(body.chat-hoja), body.chat-hoja { background: var(--bg) !important; }
	body.chat-hoja > main, body.chat-hoja > .chat-pie { transform: none !important; transition: none !important; }
	body.chat-hoja > main { border-radius: 0; }
	/* La cabecera de la hoja deja seleccionar su texto: el "no se selecciona" era para que
	   el dedo pudiera arrastrarla. */
	.sheet-header { -webkit-user-select: text; user-select: text; touch-action: auto; }
	/* La que bajaba desde ARRIBA a pantalla completa (buscar) pasa a ser una paleta
	   centrada, como la de ⌘K de cualquier app. */
	.sheet-overlay--arriba { align-items: flex-start; }
	.sheet-overlay--arriba > .sheet-panel {
		top: 8vh; bottom: auto; left: 0; right: 0; margin: 0 auto;
		width: min(42rem, calc(100vw - 3rem)); max-height: 80vh;
		border-radius: var(--radius);
	}

	/* ── LAS FILAS QUE SE DESLIZABAN SON REJILLAS ───────────────────────────────────────
	   Con ratón un carrusel sin barra es contenido escondido, y la difusión del borde y el
	   empujoncito (quitado en app.js) hacían creer que las tarjetas se arrastraban. */
	.fila-desliza, .fotos-grid, .dash-cards, .tag-list--scroll, .tabs--scrollfade {
		flex-wrap: wrap; overflow: visible;
	}
	.hay-mas-derecha, .hay-mas-izquierda { -webkit-mask-image: none !important; mask-image: none !important; }

	/* ── LA CABECERA NO REPITE LA COLUMNA ───────────────────────────────────────────────
	   El globo del chat y "Mi cuenta" ya están en la columna de la izquierda: arriba solo
	   quedan su cara (con su estado) y la campana, que es la que lleva el punto de lo que no
	   has leído. Una cara sin foto no enseña un icono de imagen rota. */
	body.has-bottomnav #botonChat, body.has-bottomnav #cuentaBtn { display: none; }
	/* (Una cara sin foto ya no se esconde: enseña su inicial — ver "SU CARA SIN FOTO" al
	   final. Escondida, en Inicio quedaba una píldora vacía arriba a la izquierda.) */
	/* El "Chat" de la columna con el panel abierto se marca solo en el color: con fondo
	   parecía una segunda pantalla activa al lado de la de verdad. */
	body.con-panel-chat.has-bottomnav > .bottomnav #navChat:not(.is-active) { background: none; }

	/* ── EL RATÓN ───────────────────────────────────────────────────────────────────────
	   Lo que se clica lo dice el cursor; lo que se pulsaba "encogiéndose" no se encoge: con
	   ratón no hay pulsación larga (es el clic derecho) y una tarjeta que se hace pequeña
	   bajo el cursor parece que se va. */
	a, button, summary, label[for], [role="button"], .calcell, .dash-card, .fotos-grid-item,
	.chip, .tabs > *, [class*="-longpress"] { cursor: pointer; }
	[class*="-longpress"].is-pressing, [class*="-editpress"].is-pressing,
	.chat-burbuja.is-pressing, .reto-msg-burbuja.is-pressing, .calcell.is-pressing { transform: none; filter: none; }
	/* Sin el "tirón" de iOS al llegar al final: en un ordenador la página se detiene. */
	html, body, main { overscroll-behavior: none; }

	/* ── BARRAS DE DESPLAZAMIENTO FINAS ─────────────────────────────────────────────────
	   Las del sistema son gruesas y grises; las de una app de escritorio cuidada son una
	   línea que casi no está hasta que la buscas. */
	* { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--text) 18%, transparent) transparent; }
	::-webkit-scrollbar { width: 10px; height: 10px; }
	::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--text) 16%, transparent); border-radius: 999px; border: 3px solid transparent; background-clip: padding-box; }
	::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--text) 30%, transparent); }
	::-webkit-scrollbar-track { background: transparent; }

	/* ── RESPONDER A UN MENSAJE: UN BOTÓN AL PASAR EL RATÓN ─────────────────────────────
	   Sustituye al deslizar la burbuja (app.js). Aparece al lado de la burbuja, hacia el
	   centro de la pantalla, y solo mientras el ratón está encima. */
	.chat-burbuja { position: relative; }
	.chat-responder-rapido {
		display: flex; align-items: center; justify-content: center;
		position: absolute; top: 50%; transform: translateY(-50%);
		width: 1.9rem; height: 1.9rem; border-radius: 50%; padding: 0;
		background: var(--surface); color: var(--muted); border: 1px solid var(--line);
		box-shadow: 0 2px 6px rgba(24, 22, 15, 0.1);
		opacity: 0; transition: opacity 0.12s ease; cursor: pointer;
		left: calc(100% + 0.45rem);
	}
	.chat-burbuja--mia > .chat-responder-rapido { left: auto; right: calc(100% + 0.45rem); }
	.chat-burbuja:hover > .chat-responder-rapido, .chat-responder-rapido:focus-visible { opacity: 1; }
	.chat-responder-rapido:hover { color: var(--accent-text); border-color: var(--accent-soft); }
}

/* ── LOS ICONOS: los de la app (IconosWeb.swift), de trazo, rojos, sin relleno ─────────────
   Todos salen de MividaIconos (app.js): en el marcado, <span data-ico="nombre"> o
   <span data-emoji-icono>🥐</span> (lo que manda el servidor, traducido a trazo). El tamaño
   lo da la letra de alrededor; el color, el contenedor — y por defecto, el acento. Los
   emojis quedan para lo que escribe la gente (reacciones, mensajes). */
.ico { width: 1.15em; height: 1.15em; vertical-align: -0.2em; flex-shrink: 0; stroke: currentColor; fill: none; }
.ico-chip, .ico-lugar, .ico-boton, [data-ico]:not(.ico-suelto), [data-emoji-icono] { color: var(--accent-text); }
.ico-chip, .ico-boton { display: inline-flex; align-items: center; }
/* Un botón o chip con su icono delante no se parte: el icono se quedaba solo arriba y
   el texto debajo (las categorías de Fotos en el móvil). */
button:has(> .ico), a.button:has(> .ico), .chip:has(> .ico) { white-space: nowrap; }
/* EL ICONO SUELTO de un botón (la X de una hoja, el + de añadir, la campana): el dibujo
   es el de todos, y el COLOR lo decide el botón que lo lleva — blanco sobre rojo, rojo
   sobre blanco —, como hacía el <svg> que había antes. Sin caja propia: el botón lo
   centra igual que antes. */
.ico-suelto { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
/* Sobre un fondo rojo (botón de acento, chip activo) el trazo va del color del texto. */
.button--accent [data-ico], .button--accent [data-emoji-icono],
.is-active > [data-ico], .is-active > [data-emoji-icono],
.chip.is-active [data-ico], .chip.is-active [data-emoji-icono] { color: inherit; }
/* La barra de abajo del móvil lleva el trazo blanco sobre su disco rojo: manda su regla. */
.bottomnav-icon[data-ico] { color: var(--accent-contrast); }
@media (min-width: 1100px) {
	body.has-bottomnav > .bottomnav .bottomnav-icon[data-ico] { color: var(--accent-text); }
}

/* ═══ LAS PIEZAS COMUNES QUE FALTABAN (repaso del escritorio, 2026-10-01) ═══════════════════
   Rafa: "una cosa profesional, fina, que respire a lo de la app". Lo que fallaba no era una
   pantalla: eran piezas sin carcasa que cada pantalla dejaba a su suerte. Van aquí, una vez. */

/* UN CAMPO SIN CLASE YA NO ES EL DEL NAVEGADOR. "Pega el enlace" de Música salía con el borde
   hundido de Chrome. Con :where() la regla pesa CERO: cualquier campo que ya tenga su estilo
   (por clase o por pantalla) lo conserva, y solo se viste lo que estaba desnudo. */
:where(input:not([type]), input[type="text"], input[type="url"], input[type="search"],
       input[type="email"], input[type="number"], input[type="tel"], input[type="password"],
       input[type="date"], input[type="time"], input[type="datetime-local"], select, textarea) {
	font: inherit; font-size: 0.95rem; color: var(--text);
	background: var(--surface); border: 1px solid var(--line); border-radius: 0.75rem;
	padding: 0.6rem 0.85rem; min-height: 2.6rem; box-sizing: border-box;
	transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
:where(input:not([type]), input[type="text"], input[type="url"], input[type="search"],
       input[type="email"], input[type="number"], input[type="tel"], input[type="password"],
       input[type="date"], input[type="time"], input[type="datetime-local"], select, textarea):focus {
	outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
:where(input, textarea)::placeholder { color: var(--muted); opacity: 0.85; }
/* Las casillas y los botones de opción, del rojo de la marca y no del azul del sistema. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }

/* UNA FOTO QUE TODAVÍA NO HA LLEGADO no enseña el icono de imagen rota del navegador (la cara
   de la pareja en Inicio salía así mientras no había foto). */
img[src=""] { visibility: hidden; }

/* LA INICIAL, no el nombre entero, en el círculo de Mi cuenta sin foto: "Prueba" se salía
   del disco. Se escribe el nombre y se enseña su primera letra. */
.avatar-inicial { display: block; font-size: 0; line-height: 1; }
.avatar-inicial::first-letter { font-size: 1.8rem; text-transform: uppercase; }

/* EL AVISO EN TRAZO: el icono del tipo, rojo y del tamaño del cuadro. */
.aviso-generico svg { width: 1.25rem; height: 1.25rem; color: var(--accent-text); }
.aviso-icono svg { width: 0.72rem; height: 0.72rem; color: var(--accent-text); }

/* "VINCULAR ESTE ORDENADOR" en el chat se salía por la derecha del panel: una línea que cabe,
   discreta y centrada, como los avisos del sistema dentro de un hilo. */
.chat-cifrado-vincular {
	display: flex !important; align-items: center; justify-content: center; gap: 0.35rem;
	max-width: calc(100% - 2rem); margin: 0.5rem auto !important; white-space: normal;
	font-size: 0.8rem !important; color: var(--muted) !important; text-align: center;
}

/* LA FILA DE UNA LISTA (Música, Podcasts): imagen, título, qué es, detalle y la ★ a la derecha,
   como FilaDeListado en iOS. Lo secundario —abrir fuera, quitar— no se repite en cada fila:
   aparece al pasar el ratón (o con el foco del teclado). En el móvil, sin ratón, se queda
   como estaba: ahí no hay "pasar por encima". */
#musicaLista > li > .card, #podcastsLista > li > .card { border-radius: 0.9rem; transition: background 0.12s ease, box-shadow 0.15s ease; }
#musicaForm, #podcastsForm { border-radius: 0.9rem; }
.musica-quitar, .podcasts-quitar { color: var(--muted) !important; }
.musica-quitar:hover, .podcasts-quitar:hover { color: var(--bad) !important; }
/* Escondido con display y no con opacidad: escondido pero ocupando sitio, en una ventana
   estrecha se comía la columna del título (se vio letra a letra en vertical). Y solo con
   anchura de escritorio: por debajo, la fila de siempre. */
@media (hover: hover) and (pointer: fine) and (min-width: 900px) {
	#musicaLista > li > .card > span:last-child,
	#podcastsLista > li > .card > span:last-child { flex-direction: row-reverse !important; align-items: center !important; gap: 0.25rem !important; }
	#musicaLista > li > .card:hover, #podcastsLista > li > .card:hover { background: var(--tint); }
	#musicaLista > li :is(a.button--light, .musica-quitar),
	#podcastsLista > li :is(a.button--light, .podcasts-quitar) { display: none; }
	#musicaLista > li:is(:hover, :focus-within) :is(a.button--light, .musica-quitar),
	#podcastsLista > li:is(:hover, :focus-within) :is(a.button--light, .podcasts-quitar) { display: inline-flex; }
	#musicaLista a.button--light, #podcastsLista a.button--light { padding: 0.35rem 0.8rem; font-size: 0.82rem; }
}

/* ═══ SEGUNDA PASADA DEL ESCRITORIO (2026-10-01) ═════════════════════════════════════════ */

/* EL ANCHO DE UNA PANTALLA, una vez: lo que antes era un max-width a mano en cada una. */
.pantalla { max-width: var(--ancho-module); }

/* LOS EVENTOS YA HECHOS: tres columnas fijas (qué · de quién fue la idea · cuándo), cada dato
   en el mismo sitio en todas las filas. En el móvil, la fecha a la derecha y el resto debajo
   del título. */
.lista-realizados { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.45rem; }
.fila-realizado {
	display: grid; grid-template-columns: minmax(0, 1fr) auto 7rem; align-items: center; gap: 1rem;
	padding: 0.75rem 1rem; background: var(--surface); border: 1px solid var(--line); border-radius: 0.9rem;
}
.fila-realizado-titulo { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fila-realizado-quien { font-size: 0.8rem; color: var(--muted); white-space: nowrap; }
.fila-realizado-fecha {
	font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
	color: var(--accent-text); text-align: right; white-space: nowrap;
}
@media (max-width: 600px) {
	.fila-realizado { grid-template-columns: minmax(0, 1fr) auto; row-gap: 0.15rem; }
	.fila-realizado-quien { grid-column: 1; grid-row: 2; }
	.fila-realizado-fecha { grid-column: 2; grid-row: 1 / 3; }
}

/* LAS SUGERENCIAS, en rejilla: una columna en el móvil, las que quepan en el ordenador. */
.rejilla-sugerencias { display: grid; gap: 1rem 1.2rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr)); }

@media (min-width: 1100px) {
	/* LA CABECERA MIDE LO MISMO EN TODAS. La altura la daba la campanita, y en Avisos —que no
	   la lleva, porque ya estás en ellos— la barra salía más baja y el título más arriba. */
	.topbar { min-height: 4.4rem; box-sizing: border-box; }

	/* FOTOS: una rejilla que llena el ancho, con las fotos cuadradas y más grandes, en vez de
	   una tira de cuadritos de 118 px pegados a la izquierda. */
	#fotosCategoriaRejilla {
		display: grid !important; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: 0.6rem;
	}
	#fotosCategoriaRejilla .fotos-grid-item { width: auto; height: auto; aspect-ratio: 1; }
	#fotosCategoriaRejilla .fotos-grid-item img { width: 100%; height: 100%; object-fit: cover; }

	/* LAS FILAS QUE SE TOCAN dicen que se pueden tocar. */
	.fila-realizado { transition: border-color 0.12s ease; }
	.fila-realizado:hover { border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }
	.chip { transition: border-color 0.12s ease, background 0.12s ease; }
	.chip:not(.is-selected):not(.is-active):hover { border-color: var(--accent); }
}

/* INICIO A PANTALLA COMPLETA: en una pantalla grande, las secciones de lo último en TRES
   columnas en vez de dos; la cabecera de las caras y las fotos siguen a todo lo ancho. */
@media (min-width: 1600px) {
	body.has-bottomnav:not(.chat-hoja) .module-dash { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ═══ TERCERA PASADA: CABECERA DE INICIO, HERRAMIENTAS DE CABECERA, FOTOS ═════════════════ */

/* Lo que el buscador de la cabecera deja fuera. */
.oculta-por-busqueda { display: none !important; }
/* Las herramientas de la cabecera son de escritorio: en el móvil cada pantalla ya tiene su
   campo y su botón de añadir a mano, y la barra no da para más. */
.topbar-herramientas { display: none; }
.status--pequeno { font-size: 0.85rem; }
/* Las dos caras de Inicio son botones (abren el álbum de cada uno) que no deben parecerlo. */
.pareja-hero-foto .ver-album {
	padding: 0; border: none; background: none; border-radius: 50%; cursor: pointer; width: 100%; height: 100%;
}

/* LA PANTALLA DE FOTOS, sin estilos en línea: sus tres piezas con nombre. */
.fotos-chips { gap: 0.4rem; margin-top: 0.8rem; padding-bottom: 0.3rem; }
.fotos-rejilla { flex-wrap: wrap; margin-top: 0.6rem; }
.fotos-vacio { margin-top: 1rem; }
.fotos-borrar-categoria { margin-top: 1rem; color: var(--bad); font-size: 0.9rem; }

@media (min-width: 1100px) {
	/* BUSCAR Y "+" A LA DERECHA DE LA CABECERA (app.js, HERRAMIENTAS): el mismo sitio y la
	   misma forma en todas las pantallas que tienen algo que buscar o añadir. */
	.topbar-herramientas { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }
	.topbar-herramientas + .barra-grupo--der { margin-left: 0.4rem; }
	.topbar-buscar {
		display: flex; align-items: center; gap: 0.45rem; height: 2.4rem; padding: 0 0.85rem;
		border: 1px solid var(--line); border-radius: 999px; background: var(--surface);
		color: var(--muted); transition: border-color 0.12s ease, box-shadow 0.12s ease;
	}
	.topbar-buscar:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
	.topbar-buscar svg { width: 1.05rem; height: 1.05rem; flex-shrink: 0; color: var(--accent-text); }
	.topbar-buscar input {
		border: 0 !important; background: none !important; box-shadow: none !important; outline: none;
		padding: 0 !important; min-height: 0 !important; width: 13rem; font: inherit; font-size: 0.9rem;
	}
	.topbar-mas {
		display: inline-flex; align-items: center; justify-content: center; width: 2.4rem; height: 2.4rem;
		border-radius: 50%; border: 0; background: var(--accent); color: var(--accent-contrast); cursor: pointer;
		transition: transform 0.12s ease, box-shadow 0.12s ease;
	}
	.topbar-mas svg { width: 1.2rem; height: 1.2rem; stroke: currentColor; }
	.topbar-mas:hover { transform: translateY(-1px); box-shadow: 0 6px 16px -6px rgba(197, 44, 43, 0.6); }
}

/* ══ LO QUE ESTABA ESCRITO EN LÍNEA ═══════════════════════════════════════════════════════
   Inicio, Calendario y Gustos llevaban casi trescientos `style="…"`: cada botón de cerrar,
   cada fila con hueco, cada aviso de formulario con su propio número. Dos hojas de la misma
   pantalla acababan con aires distintos y cambiar uno era buscarlo en tres ficheros. Ahora
   son piezas con nombre, aquí, y la pantalla solo dice QUÉ es cada cosa.
   Lo único que sigue en línea es DATO, no estilo: el ancho de una barra de progreso
   (`width:{{pct}}%`), el color que cada uno eligió para sí (`--color-yo`) y el del punto
   de "realizado" de cada persona. */

/* Filas, columnas y rejillas */
.fila { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.fila--arriba { align-items: flex-start; }
.fila--base { align-items: baseline; }
.fila--entre { justify-content: space-between; }
.fila--fin { justify-content: flex-end; }
.fila--envuelve { flex-wrap: wrap; }
.fila--junta { gap: 0.3rem; }
.fila--ancha { gap: 0.8rem; }
.columna { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.columna--holgada { gap: 0.35rem; }
.rejilla { display: grid; gap: 0.6rem; }
.rejilla-dos { display: grid; grid-template-columns: 1fr 1fr; gap: 0.8rem; margin-top: 1rem; }
.fila[hidden], .columna[hidden], .rejilla[hidden], .fila-opciones[hidden], .fila-acciones[hidden] { display: none; }
.estira { flex: 1 1 auto; min-width: 0; }
.no-encoge { flex-shrink: 0; }
.encoge { min-width: 0; }
.bloque { display: block; }
.entero { width: 100%; }
.alinea-inicio { justify-self: start; }
.recorta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.sin-margen { margin: 0; }
.relativo { position: relative; }
.texto-fuerte { font-weight: 600; }
.texto-nota { font-size: 0.85rem; }
.texto-peque { font-size: 0.78rem; }
.enlace-llano { text-decoration: none; color: inherit; }
/* Lo que el SERVIDOR decide esconder (estando solo, por ejemplo) y nadie vuelve a enseñar. */
.oculto { display: none !important; }
/* Lo que empieza escondido y enseña el JS con `style.display` (por eso sin !important). */
.oculto-js { display: none; }

/* Listas sin viñetas: la de los eventos de un día, la de las notas de un evento. */
.lista-llana { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.lista-llana--hilo { display: flex; flex-direction: column; gap: 0.35rem; }
.lista-llana--debajo { margin-top: 0.6rem; }

/* LO QUE SE MANTIENE PULSADO no se selecciona ni saca el menú del sistema: eso es la
   pulsación larga (reaccionar, editar). Y en las listas que se desplazan en vertical el
   dedo sigue moviendo la lista. */
[class*="-longpress"], [class*="-editpress"], .sugerencia-pasar {
	-webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
.agradecimiento-longpress, .agradecimiento-editpress, .gusto-longpress { touch-action: pan-y; }
.editar-favorito { cursor: pointer; }

/* Botones */
.boton-icono {
	display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
	background: none; border: none; padding: 0.3rem; cursor: pointer;
	color: var(--muted); text-decoration: none;
}
.boton-icono--peligro { color: var(--bad); }
.button.button--peque { font-size: 0.8rem; padding: 0.5rem 0.85rem; white-space: nowrap; }
.button.button--mini { font-size: 0.85rem; }
.button.button--icono { padding: 0.5rem 0.6rem; display: flex; align-items: center; flex-shrink: 0; }
.button.button--enlace { padding: 0.4rem 0.55rem; text-decoration: none; }
.button.button--texto { padding: 0.15rem 0; font-size: 0.8rem; align-self: flex-start; }
.button.button--barra { padding: 0.4rem 0.75rem; font-size: 0.85rem; white-space: nowrap; }
.button.button--entero { width: 100%; }
label.button { cursor: pointer; }
.botones { display: flex; gap: 0.6rem; }

/* Hojas: la cabecera con su título y sus iconos en una fila, y el pie con "Borrar" a un
   lado y "Cancelar · Guardar" al otro. */
.sheet-header--fila { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; }
.sheet-header--fila.fila--arriba { align-items: flex-start; }
.sheet-body--holgado { gap: 1rem; }
.sheet-footer--entre { justify-content: space-between; }
.sheet-footer--entero { justify-content: stretch; }
.sheet-footer--entero > form { width: 100%; }
.acciones-cabecera { display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0; }
.acciones-cabecera--juntas { gap: 0.1rem; }

/* Textos de formulario */
.fact-label--llano { text-transform: none; letter-spacing: 0; }
.fact-label--fino { font-weight: 400; }
.fact-label--titulo { margin: 0 0 0.5rem; }
.chip-label--campo { display: block; margin: 1rem 0 0.3rem; }
.chip-label--campo.chip-label--arriba { margin-top: 0; }
.status--form { margin: 0.5rem 0 0; font-size: 0.85rem; }
.status--suelto { margin: 0; font-size: 0.85rem; }
.visit-line--intro { margin: 0 0 0.6rem; }
.visit-line--aviso { margin: 0.8rem 0 0.4rem; }
.nota-campo { color: var(--muted); margin: 0.4rem 0 0; }
.campo-texto {
	width: 100%; padding: 0.5rem 0.7rem; border: 1px solid var(--line);
	border-radius: var(--radius-control); font: inherit; font-size: 0.95rem;
}
.campo-fecha { flex: 1; min-width: 9rem; }
.check { width: 1.1rem; height: 1.1rem; flex-shrink: 0; }
.check--peque { width: 1rem; height: 1rem; }
.check--grande { width: 1.2rem; height: 1.2rem; }
.casilla { display: flex; align-items: center; gap: 0.6rem; cursor: pointer; }
.casilla--apagada { opacity: 0.7; cursor: default; }
.fila-opciones { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.fila-opciones--separada { margin-top: 0.6rem; }
.fila-opciones input[type="radio"] { margin-right: 0.3rem; }
.fila-acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.6rem; }
.form-en-linea { display: flex; gap: 0.5rem; margin-top: 1rem; }

/* Tarjetas */
.wrap--module { max-width: var(--ancho-module); }
.card.card--compacta { padding: 0.9rem 1rem; }
.card-titulo { display: block; margin-bottom: 0.6rem; }
.mes-nav { display: flex; align-items: center; justify-content: space-between; margin: 0.9rem 0 0.5rem; }
.mes-nav .button { padding: 0.3rem 0.7rem; }
.titulo-mes { font-size: 1.1rem; margin: 0; text-transform: capitalize; }

/* ── INICIO ── */
.chips-de-fotos { gap: 0.4rem; margin-bottom: 0.5rem; padding-bottom: 0.2rem; }
.chip.chip--enlace { white-space: nowrap; text-decoration: none; }
.sugerencia-pasar { position: relative; }
.sugerencia-pasar .sugerencia-categoria { margin: 0; }
.sugerencia-pasar .sugerencia-linea { margin: 0.3rem 0 0; display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.sugerencia-pasar .sugerencia-nombre { font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sugerencia-pasar .sugerencia-etiquetas { margin: 0.35rem 0 0; display: flex; flex-wrap: wrap; gap: 0.3rem; }
.sugerencia-pasar .sugerencia-origen { margin: 0.4rem 0 0; font-size: 0.68rem; color: var(--muted); }
.barra-flotante--sugerencia { gap: 0.2rem; padding: 0.4rem 0.5rem; }
.barra-emojis { display: flex; align-items: center; }
.barra-divisor { width: 1px; align-self: stretch; background: var(--line); margin: 0 0.2rem; }
.dash-list > .agradecimiento-longpress { position: relative; }
.coach-banner.coach-banner--neutro { border-color: var(--line); margin-bottom: 0.5rem; }
.coach-banner-icono.coach-banner-icono--tinte { background: var(--tint); color: var(--accent-text, var(--accent)); }

/* ── CALENDARIO ── */
.resumen-dos { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; margin-top: 0.9rem; }
.resumen-dos--uno { grid-template-columns: 1fr; }
.card.tarjeta-resumen {
	min-width: 0; padding: 0.7rem 0.8rem; gap: 0.25rem;
	display: flex; flex-direction: column; justify-content: flex-start;
}
button.tarjeta-resumen { font: inherit; color: inherit; text-align: left; cursor: pointer; }
.tarjeta-resumen > .fact-label { margin: 0; white-space: nowrap; }
.objetivo-card--logrado > .fact-label { color: inherit; opacity: 0.85; }
.tarjeta-resumen-titulo { margin: 0; font-weight: 600; font-size: 0.9rem; }
.tarjeta-resumen-sub { margin: 0.1rem 0 0; font-size: 0.78rem; }
.tarjeta-resumen-vacio { margin: 0; font-size: 0.78rem; }
.ranking-detalle { display: grid; gap: 0.4rem; }
.ranking-detalle-fila { display: flex; justify-content: space-between; gap: 0.6rem; font-size: 0.85rem; }
.tabla-semanas { width: 100%; border-collapse: collapse; }
.tabla-semanas tr { border-bottom: 1px solid var(--line); }
.tabla-semanas th { padding: 0.5rem 0; font-size: 0.8rem; color: var(--muted); font-weight: 600; text-align: left; }
.tabla-semanas td { padding: 0.6rem 0; font-size: 0.88rem; }
.tabla-semanas th:last-child, .tabla-semanas td:last-child { text-align: right; }
.ganador { display: inline-flex; align-items: center; gap: 0.3rem; }
.reto-avatar-mini.reto-avatar-mini--solapa { margin-right: -0.5rem; }
/* La inicial de cada día en SU color: el de la pantalla (--color-yo / --color-pareja, en el
   .wrap), no uno escrito en cada casilla. */
.cal-inicial--yo { background: var(--color-yo); }
.cal-inicial--pareja { background: var(--color-pareja); }
.card.evento-fila {
	padding: 0.7rem 0.9rem; display: flex; justify-content: space-between; align-items: center;
	gap: 0.6rem; font-size: 0.92rem; border: 1.5px solid var(--accent); cursor: pointer;
}
.evento-fila-titulo { font-weight: 600; }
.evento-fila-hora { color: var(--accent-text); font-weight: 600; font-size: 0.85rem; flex-shrink: 0; }
.boton-fecha {
	font-size: 0.72rem; font-weight: 400; color: var(--muted);
	background: none; border: none; padding: 0; cursor: pointer; text-decoration: underline;
}
.hito-btn.hito-btn--separado { margin-right: 0.3rem; }
.reto-cabecera { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.6rem; }
.reto-entradas-toggle {
	display: flex; align-items: center; gap: 0.3rem; background: none; border: none;
	padding: 0.4rem 0 0.2rem; margin: 0; color: var(--muted); font-size: 0.82rem;
	cursor: pointer; font-family: inherit;
}
.reto-entradas-flecha { transition: transform 0.25s ease; }
ul.reto-entradas {
	list-style: none; margin: 0.2rem 0 0; padding: 0 0 0.9rem;
	display: flex; flex-direction: column; gap: 0.35rem;
}
.mensaje-acciones { display: none; align-items: center; gap: 0.3rem; margin-left: 0.3rem; }
.mensaje-accion-editar, .mensaje-accion-borrar {
	width: 1.7rem; height: 1.7rem; border-radius: 50%; cursor: pointer;
	display: flex; align-items: center; justify-content: center;
	background: var(--surface); border: 1px solid var(--line); color: var(--muted);
}
.reto-vacio { margin: 0.4rem 0 0; font-size: 0.85rem; }
.reto-texto-form { margin-top: 0.6rem; }

/* ── GUSTOS ── */
.band.band--lista { padding-bottom: 6rem; }
.gustos-quien { display: flex; align-items: center; flex-wrap: nowrap; gap: 0.4rem; margin-top: 0.8rem; }
.gustos-quien-anadir { margin-left: auto; flex-shrink: 0; }
.tabs.tabs--fila {
	display: flex; align-items: center; flex-wrap: nowrap; gap: 0.5rem;
	overflow-x: auto; padding-bottom: 0.3rem; margin-top: 0.8rem;
}
.gustos-panel { margin-top: 1.2rem; }
.card.aviso-bloqueo { padding: 0.8rem 1rem; margin: 0 0 0.8rem; font-size: 0.85rem; }
.subtitulo-lista { font-size: 1rem; margin: 1.4rem 0 0.6rem; }
.gustos-panel .rank-titulo { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.rank-titulo-linea { display: flex; align-items: center; gap: 0.3rem; min-width: 0; }
.status-dot {
	display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center;
	width: 15px; height: 15px; border-radius: 50%;
}
.acciones-lista { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 1rem; }
.anadir-en-lista { margin-top: 1rem; }
.categoria-fila { display: flex; align-items: center; gap: 0.6rem; padding: 0.5rem 0; border-bottom: 1px solid var(--line); }
.categoria-planes { display: flex; align-items: center; gap: 0.35rem; flex-shrink: 0; cursor: pointer; }
.editar-cabecera { display: flex; align-items: center; gap: 1rem; padding: 0.3rem 0 0.2rem; }

/* ── SU CARA SIN FOTO ── En la cabecera se ve su INICIAL, como en el resto de la app: sin
   foto, la píldora de arriba a la izquierda se quedaba vacía (en el escritorio el globo del
   chat está en la columna, así que no quedaba nada) y la ficha de los dos no se podía abrir. */
.topbar-pareja-inicial {
	display: none; --tam: 2.2rem; width: var(--tam); height: var(--tam);
	background: var(--tint); color: var(--accent-text); font-family: var(--font-display);
}
.topbar-pareja:has(#topbarParejaFoto[src=""]) .topbar-pareja-inicial { display: block; }
.topbar-pareja:has(#topbarParejaFoto[src=""]) #topbarParejaFoto { display: none; }

/* ══ LA PORTADA, LA DE iOS ═════════════════════════════════════════════════════════════════
   Rafa, 2026-10-01: "tiene que ser COMO LA DE IPHONE en el escritorio... las 3 plataformas
   unificadas". Cada pieza tiene su gemela en iOS y se llama por ella:
     .portada-cab          PortadaEnDiapositivas / CabeceraEnSolitario (fotos detrás, caras con aro)
     .portada-seccion-cab  CabeceraSeccion (título en versalitas, "Ver todos ›" a su altura)
     .portada-tira         TiraDeUltimosAnadidos / AsistenteDePortada (se desliza; ≤2, a lo ancho)
     .portada-ficha        la tarjeta de lo último (imagen cuadrada, qué es, título, detalle)
     .portada-evento       tarjetaDePlan (media tarjeta; el próximo, destacado)
     .portada-saldo        SaldoDeGastosDePortada (rojo, cara → flecha → cara)
     .portada-nota         TarjetaDeTarea (nota amarilla, un pelo ladeada)
     .portada-consejo      ConsejoDePortada
     .portada-accesos      AccesosDeInicio ("Qué más compartimos")
   En el escritorio NO cambia el orden: es una columna ancha, la cabecera se hace banda y las
   tiras dejan de deslizarse y enseñan todas sus tarjetas a la vez (con ratón, un carrusel sin
   barra es contenido escondido). */
:root { --nota: #FFF1BF; --nota-texto: #3A3220; }
@media (prefers-color-scheme: dark) { :root { --nota: #3A3220; --nota-texto: #F2EFE8; } }

.portada { --margen: 1.25rem; padding-left: var(--margen); padding-right: var(--margen); }
.portada-cuerpo { display: flex; flex-direction: column; gap: 1rem; padding-bottom: 1.5rem; }

/* ── LA CABECERA ── */
.portada-cab {
	position: relative; isolation: isolate; overflow: hidden;
	display: flex; flex-direction: column; justify-content: flex-end;
	min-height: min(40vh, 22rem);
	/* A todo lo ancho y desde el borde de arriba, como en iOS: debajo de la hora y de los
	   dos grupos flotantes. */
	margin: calc(-1 * var(--hueco-arriba, 3.4rem)) calc(-1 * var(--margen)) 0;
	padding: calc(var(--hueco-arriba, 3.4rem) + 1rem) var(--margen) 0.6rem;
}
.portada-cab--fotos { min-height: 50vh; }
.portada-cab-fondo {
	position: absolute; inset: 0; z-index: -1; display: block;
	background: linear-gradient(to bottom, var(--accent-soft), var(--bg));
}
.portada-cab-capa {
	position: absolute; inset: 0; background-size: cover; background-position: center;
	opacity: 0; transition: opacity 2.4s ease;
}
.portada-cab-capa.is-visible { opacity: 1; animation: portadaAcercarse 14s ease-out both; }
/* Arriba, una sombra para que los grupos flotantes se lean sobre la foto; abajo, la foto se
   funde con el fondo de la página. */
.portada-cab--fotos .portada-cab-fondo::before,
.portada-cab--fotos .portada-cab-fondo::after { content: ""; position: absolute; left: 0; right: 0; z-index: 1; pointer-events: none; }
.portada-cab--fotos .portada-cab-fondo::before { top: 0; height: 9rem; background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)); }
.portada-cab--fotos .portada-cab-fondo::after {
	bottom: 0; height: 11rem;
	background: linear-gradient(to bottom, transparent 0%, color-mix(in srgb, var(--bg) 55%, transparent) 45%, var(--bg) 100%);
}
@keyframes portadaAcercarse { from { transform: scale(1.06); } to { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .portada-cab-capa.is-visible { animation: none; } }

.portada-cab-pie { position: relative; display: flex; flex-direction: column; align-items: center; gap: 0.6rem; pointer-events: none; }
.portada-cab-pie a, .portada-cab-pie button { pointer-events: auto; }
.portada-caras { display: flex; align-items: flex-start; justify-content: center; gap: 0.3rem; }
.portada-cara { position: relative; width: 8.2rem; display: flex; flex-direction: column; align-items: center; padding-bottom: 0.75rem; }
/* La cara con su aro de colores que gira (el AroBrillante de iOS): el aro es un borde de
   degradado cónico detrás de un círculo blanco. */
.portada-cara-boton {
	position: relative; width: 6.1rem; height: 6.1rem; padding: 0; border: 2px solid #fff; border-radius: 50%;
	/* Opaca: sin foto, la inicial va sobre el rosa de la marca y no sobre la foto de detrás. */
	background: linear-gradient(var(--accent-soft), var(--accent-soft)), var(--surface);
	cursor: pointer; display: grid; place-items: center; text-decoration: none;
	box-shadow: 0 5px 12px rgba(0, 0, 0, 0.28);
}
.portada-cara-boton::before {
	content: ""; position: absolute; inset: -0.45rem; border-radius: 50%; z-index: -1;
	background: conic-gradient(from var(--giro, 0deg), var(--accent), #FFC766, #FF6B9E, var(--accent), #C766FA, #FF9E4D, var(--accent));
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));
	mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));
	animation: portadaAro 14s linear infinite;
}
@property --giro { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
@keyframes portadaAro { to { --giro: 360deg; } }
@media (prefers-reduced-motion: reduce) { .portada-cara-boton::before { animation: none; } }
/* La foto ocupa el círculo ENTERO y no puede opinar sobre su tamaño: posicionada sobre el
   hueco (el hueco manda y la foto obedece). Con `height: 100%` dentro de una rejilla, una foto
   vertical tomaba su propio alto y salía cortada por abajo (Rafa, 2026-10-01). */
.portada-cara-boton img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.portada-cara-inicial {
	display: block; width: 100%; font-size: 0; line-height: 6rem; text-align: center;
	font-family: var(--font-display); color: var(--accent-text);
}
.portada-cara-inicial::first-letter { font-size: 2.4rem; font-weight: 700; text-transform: uppercase; }
.portada-cara-boton--hueco { background: var(--surface); border-style: dashed; border-color: var(--accent); color: var(--accent-text); font-family: var(--font-display); font-size: 2.6rem; font-weight: 700; }
.portada-cara-boton--hueco::before { display: none; }
.portada-cara-nombre {
	position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
	max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
	padding: 0.2rem 0.65rem; border-radius: 999px; background: var(--accent); color: #fff;
	font-size: 0.8rem; font-weight: 600; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.portada-cara-nombre--hueco { background: var(--surface); color: var(--accent-text); border: 1px solid var(--line); }
.portada-lazo { width: 5rem; padding-top: 2.4rem; display: flex; flex-direction: column; align-items: center; gap: 0.35rem; }
.portada-lazo svg { width: 4.1rem; height: 2.05rem; }
.portada-lazo--apagado svg { opacity: 0.45; }
.portada-tiempo { font-weight: 700; font-size: 1rem; color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.portada-musica {
	display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.95rem 0.35rem 0.4rem;
	border-radius: 999px; background: var(--surface); border: 1px solid var(--line);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12); color: var(--text); text-decoration: none; font-weight: 600; font-size: 0.92rem;
}
.portada-musica-logo { width: 1.65rem; height: 1.65rem; border-radius: 50%; background: #1DB954; color: #fff; display: grid; place-items: center; }
.portada-aniversario { font-size: 0.85rem; color: var(--accent-text); text-decoration: none; text-align: center; }

/* ── UNA SECCIÓN: su título en versalitas y su "Ver todos ›" a la misma altura ── */
.portada-seccion { margin-top: 0.6rem; min-width: 0; }
.portada-seccion-cab { display: flex; align-items: baseline; justify-content: space-between; gap: 0.8rem; margin-bottom: 0.9rem; }
.portada-seccion-titulo {
	margin: 0; font-family: var(--font); font-size: 0.92rem; font-weight: 700; line-height: 1.3;
	letter-spacing: 0.09em; text-transform: uppercase; color: var(--text);
}
.portada-cuenta { font-size: 0.8rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
.portada-ver { font-size: 0.88rem; font-weight: 600; color: var(--accent-text); text-decoration: none; white-space: nowrap; }
a.portada-ver:hover, .portada-paso:hover .portada-ver { text-decoration: underline; }
.portada-pie { margin: 0.6rem 0 0; font-size: 0.85rem; color: var(--muted); }

/* ── LAS TIRAS: se deslizan de borde a borde; con dos o menos, a partes iguales ── */
.portada-tira {
	display: flex; align-items: stretch; gap: 0.6rem; overflow-x: auto; scrollbar-width: none;
	margin: 0 calc(-1 * var(--margen)); padding: 0.1rem var(--margen) 0.4rem;
	scroll-snap-type: x proximity; scroll-padding-inline: var(--margen);
}
.portada-tira::-webkit-scrollbar { display: none; }
.portada-tira > * { scroll-snap-align: start; }
.portada-tira--anchas { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); overflow: visible; margin: 0; padding: 0; }

/* El asistente: tarjetas de ancho fijo, todas al alto de la más alta; sola, a todo lo ancho. */
.portada-paso {
	flex: 0 0 15.5rem; display: flex; flex-direction: column; gap: 0.3rem; text-decoration: none; color: inherit;
	padding: 1rem 1.1rem;
}
.portada-asistente--uno .portada-tira { overflow: visible; margin: 0; padding: 0; }
.portada-asistente--uno .portada-paso { flex: 1 1 auto; }
.portada-paso-titulo { font-size: 1.02rem; font-weight: 700; line-height: 1.3; color: var(--text); }
.portada-paso-texto { font-size: 0.86rem; color: var(--muted); line-height: 1.4; flex: 1 1 auto; }
.portada-paso .portada-ver { margin-top: 0.35rem; }

/* Una ficha de lo último: imagen cuadrada recortada a su hueco, qué es, título y detalle. */
.portada-ficha { flex: 0 0 9.25rem; width: 9.25rem; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; text-decoration: none; color: inherit; }
.portada-ficha-img {
	position: relative; display: block; width: 100%; aspect-ratio: 1; border-radius: var(--radius-control);
	overflow: hidden; background: var(--accent-soft); margin-bottom: 0.25rem;
}
.portada-ficha-img > img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portada-ficha-icono { position: absolute; inset: 0; display: grid; place-items: center; color: var(--accent-text); }
.portada-ficha-cara { position: absolute; right: 0.4rem; bottom: 0.4rem; box-shadow: 0 0 0 2px var(--surface); }
.portada-ficha-etiqueta {
	display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.7rem; font-weight: 700;
	letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent-text);
}
.portada-ficha-etiqueta .ico-chip { font-size: 0.75rem; }
.portada-ficha-titulo {
	font-size: 0.93rem; font-weight: 600; line-height: 1.3; color: var(--text);
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.portada-ficha-detalle { font-size: 0.8rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
a.portada-ficha:hover .portada-ficha-titulo { color: var(--accent-text); }
.portada-tira--anchas .portada-ficha { width: auto; }
.portada-tira--anchas .portada-ficha-img { aspect-ratio: auto; height: 10rem; }
.portada-tira--anchas .portada-ficha:only-child .portada-ficha-img { height: 12.5rem; }

/* La cara pequeña de quién (evento, ficha). */
.portada-carita {
	flex: 0 0 auto; width: 1.6rem; height: 1.6rem; border-radius: 50%; overflow: hidden; --tam: 1.6rem;
	background: var(--accent-soft); color: var(--accent-text); display: block;
}
.portada-carita img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portada-carita .avatar-inicial, .portada-saldo-cara .avatar-inicial {
	display: block; width: 100%; height: 100%; font-size: 0; line-height: var(--tam); text-align: center;
}
.portada-carita .avatar-inicial::first-letter, .portada-saldo-cara .avatar-inicial::first-letter {
	font-size: calc(var(--tam) * 0.46); font-weight: 700; text-transform: uppercase;
}

/* ── VUESTROS EVENTOS: dos medias tarjetas; el próximo, con el borde y el velo de la marca ── */
.portada-dos { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.6rem; }
.portada-evento { display: flex; flex-direction: column; gap: 0.3rem; padding: 0.95rem 1rem; text-decoration: none; color: inherit; min-height: 9rem; }
.portada-evento-cab { display: flex; align-items: center; justify-content: space-between; gap: 0.4rem; }
.portada-evento-etiqueta { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.portada-evento--proximo { border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.portada-evento--proximo .portada-evento-etiqueta { color: var(--accent-text); }
.portada-evento-titulo {
	font-size: 1.05rem; font-weight: 700; line-height: 1.3; color: var(--text);
	display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.portada-evento-lugar { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.8rem; color: var(--muted); min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.portada-evento-cuando { margin-top: auto; font-size: 0.82rem; font-weight: 600; color: var(--accent-text); }
.portada-evento-vacio { font-size: 0.88rem; color: var(--muted); }

/* ── LA ÚLTIMA FOTO: grande, con cuándo en una cápsula ── */
.portada-ultima-foto {
	position: relative; display: block; width: 100%; height: 13rem; padding: 0; border: 0; cursor: pointer;
	border-radius: var(--radius); overflow: hidden; background: var(--accent-soft);
}
.portada-ultima-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portada-ultima-foto-cuando {
	position: absolute; left: 0.6rem; bottom: 0.6rem; padding: 0.2rem 0.6rem; border-radius: 999px;
	background: rgba(0, 0, 0, 0.45); color: #fff; font-size: 0.78rem; font-weight: 600;
}

/* ── GASTOS: la única sección con el rojo de fondo ── */
.portada-seccion--sin-cab { margin-top: 1.4rem; }
.portada-saldo {
	display: flex; align-items: center; gap: 1rem; padding: 1.1rem 1.2rem; border-radius: var(--radius);
	background: var(--accent); color: #fff; text-decoration: none;
	box-shadow: 0 8px 20px -8px color-mix(in srgb, var(--accent) 60%, transparent);
}
.portada-saldo-texto { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.portada-saldo-frase { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: rgba(255, 255, 255, 0.78); }
.portada-saldo-importe { font-family: var(--font-display); font-size: 2.3rem; line-height: 1.05; letter-spacing: -0.01em; }
.portada-saldo-caras { display: flex; align-items: center; gap: 0.6rem; }
.portada-saldo-cara {
	width: 2.1rem; height: 2.1rem; border-radius: 50%; overflow: hidden; --tam: 2.1rem; flex: 0 0 auto;
	box-shadow: 0 0 0 2px #fff; background: var(--surface); color: var(--accent-text);
}
.portada-saldo-cara img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portada-saldo-flecha { position: relative; flex: 0 1 5.5rem; height: 2px; background: rgba(255, 255, 255, 0.78); }
.portada-saldo-flecha::after {
	content: ""; position: absolute; right: -2px; top: -4px;
	border-left: 8px solid rgba(255, 255, 255, 0.78); border-top: 5px solid transparent; border-bottom: 5px solid transparent;
}
.portada-saldo-igual { font-size: 1.4rem; font-weight: 700; }
.portada-saldo-pista { font-size: 0.8rem; color: rgba(255, 255, 255, 0.78); }
.portada-saldo-ir { flex: 0 0 auto; color: rgba(255, 255, 255, 0.78); }

/* ── TAREAS: notas adhesivas ── */
.portada-tira--notas { padding-top: 0.4rem; padding-bottom: 0.7rem; }
.portada-nota {
	flex: 0 0 13rem; display: flex; flex-direction: column; gap: 0.3rem; padding: 0.8rem 0.8rem;
	border-radius: var(--radius); background: var(--nota); color: var(--nota-texto);
	box-shadow: 1px 3px 8px rgba(0, 0, 0, 0.14);
}
.portada-nota--izq { transform: rotate(-1.2deg); }
.portada-nota--der { transform: rotate(1.2deg); }
.portada-nota-cab { display: flex; align-items: center; gap: 0.35rem; }
.portada-nota-marcar { width: 2rem; height: 2rem; margin: -0.4rem -0.2rem -0.4rem -0.45rem; padding: 0; border: 0; background: none; color: var(--muted); cursor: pointer; display: grid; place-items: center; }
.portada-nota-marcar:hover { color: var(--accent-text); }
.portada-nota.is-hecha .portada-nota-marcar { color: var(--ok); }
.portada-nota.is-hecha .portada-nota-titulo { text-decoration: line-through; color: var(--muted); }
.portada-nota-cuando { font-size: 0.74rem; font-weight: 600; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.portada-nota-cuando--hoy { color: var(--accent-text); }
.portada-nota-cuando--vencida { color: var(--bad); }
.portada-nota-candado { color: var(--muted); }
.portada-nota-titulo {
	font-size: 0.95rem; line-height: 1.35; color: inherit; text-decoration: none;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.portada-tira--anchas .portada-nota { flex: 1 1 auto; }
.portada-nada { padding: 1rem 1.1rem; font-size: 0.9rem; color: var(--muted); text-decoration: none; flex: 1 1 auto; }

/* ── EL CONSEJO DEL COACH: rojo, como su tarjeta en iOS ── */
.portada-consejo {
	display: flex; flex-direction: column; gap: 0.55rem; padding: 1.1rem 1.2rem; border-radius: var(--radius);
	background: var(--accent); color: #fff; text-decoration: none;
}
.portada-consejo-etiqueta { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: rgba(255, 255, 255, 0.78); }
.portada-consejo-ejercicio { font-size: 1.15rem; line-height: 1.35; }
.portada-consejo-texto { font-size: 0.92rem; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; }
.portada-consejo-privado { display: flex; gap: 0.5rem; align-items: flex-start; padding: 0.6rem 0.75rem; border-radius: var(--radius-control); background: rgba(255, 255, 255, 0.14); font-size: 0.85rem; }
.portada-consejo-privado strong { display: block; font-size: 0.8rem; }
.portada-consejo-ir { font-size: 0.88rem; font-weight: 600; }

/* ── QUÉ MÁS COMPARTIMOS: círculos de cuatro en fila ── */
.portada-accesos { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem 0.3rem; }
.portada-acceso { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; text-decoration: none; color: var(--text); min-width: 0; }
.portada-acceso-circulo {
	width: 3.6rem; height: 3.6rem; border-radius: 50%; display: grid; place-items: center;
	background: var(--surface); border: 1px solid var(--line); color: var(--accent-text);
	transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.portada-acceso:hover .portada-acceso-circulo { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.portada-acceso-nombre { font-size: 0.8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }

/* La propuesta de pareja, estando solo. */
.portada-propuesta { display: flex; flex-direction: column; gap: 0.3rem; padding: 1rem 1.1rem; }
.portada-propuesta-titulo { font-size: 1.02rem; }
.portada-propuesta-texto { margin: 0; font-size: 0.86rem; color: var(--muted); }

/* ── EN EL ESCRITORIO: la misma columna, más ancha; la cabecera, una banda ── */
@media (min-width: 900px) {
	.portada { --margen: 0; max-width: 64rem; margin-inline: auto; }
	.portada-cab {
		margin: 0.4rem 0 0; padding: 2.5rem 1.5rem 1.4rem; border-radius: 1.4rem;
		min-height: 18rem; box-shadow: 0 18px 40px -24px rgba(24, 22, 15, 0.45);
	}
	.portada-cab--fotos { min-height: 22rem; }
	.portada-cab--fotos .portada-cab-fondo { background: #1c1712; }
	.portada-cab--fotos .portada-cab-fondo::after { height: 9rem; }
	.portada-cab--fotos .portada-tiempo { color: var(--text); }
	.portada-cara { width: 9.5rem; }
	.portada-cara-boton { width: 7rem; height: 7rem; }
	.portada-cara-inicial { line-height: 6.9rem; }
	.portada-cuerpo { gap: 1.2rem; padding-top: 0.4rem; }
	/* Las tiras dejan de deslizarse: todas sus tarjetas a la vista, en filas. */
	/* Hasta seis, en UNA fila a partes iguales; con más, en filas de las que quepan. */
	.portada-tira { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); overflow: visible; margin: 0; padding: 0; }
	.portada-tira:has(> :nth-child(7)) { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); }
	.portada-tira.portada-tira--pasos { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
	.portada-tira--notas { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); padding: 0.3rem 0.2rem 0.4rem; }
	.portada-ficha { width: auto; }
	.portada-tira--anchas { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.portada-tira--anchas > :only-child { grid-column: 1 / -1; }
	.portada-tira--anchas .portada-ficha-img { height: 13rem; }
	.portada-tira--anchas .portada-ficha:only-child .portada-ficha-img { height: 16rem; }
	.portada-ultima-foto { height: 20rem; }
	.portada-evento { min-height: 10rem; padding: 1.1rem 1.25rem; }
	.portada-accesos { grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr)); }
	a.portada-evento:hover, a.portada-paso:hover, a.portada-nada:hover { box-shadow: 0 2px 4px rgba(24, 22, 15, 0.05), 0 16px 32px -12px rgba(24, 22, 15, 0.22); }
	a.portada-ficha:hover .portada-ficha-img > img { transform: scale(1.03); }
	.portada-ficha-img > img { transition: transform 0.25s ease; }
}

@media (min-width: 1100px) {
	/* Con ratón las categorías se ven todas, partidas en dos filas si hace falta: una fila
	   que solo se desliza escondía la última (y el engranaje) detrás del borde. */
	.tabs.tabs--fila { flex-wrap: wrap; overflow: visible; }
	/* El "+" ya está en la cabecera (junto al buscador): el "+ Añadir" de la fila de
	   "Mis gustos" era el mismo botón dos veces, uno debajo del otro. */
	body:has(.topbar-mas) .gustos-quien-anadir { display: none; }
}

/* ══ LAS PANTALLAS DE AJUSTES: MI CUENTA, EL COACH, AVISOS Y EL CHAT, SIN ESTILOS EN LÍNEA ══
   2026-10-01. Llevaban casi doscientos `style="…"`: cada tarjeta de Mi cuenta con su relleno,
   cada etiqueta de campo con su gris, cada hoja con su botón de cerrar pintado a mano. Ahora
   son piezas con nombre, y una tarjeta de ajustes es SIEMPRE `.ajuste`: su rótulo
   (`.ajuste-titulo`), su explicación (`.ajuste-texto`) y lo que se toca. Cambiarla aquí las
   cambia todas. Lo único que sigue en línea son los anchos que manda el servidor (el balance
   del coach, la barra del saldo): son datos, no estilo. */
.sin-margen { margin: 0; }
.ajustes-pestanas { display: flex; gap: 0.4rem; margin-top: 0.6rem; }
.card.ajuste { padding: 1.2rem 1.4rem; margin-top: 1rem; }
.card.ajuste--aparte { margin-top: 2.4rem; }
.ajuste--perfil { display: flex; align-items: center; gap: 1.2rem; }
.ajuste-avatar-caja { position: relative; flex-shrink: 0; }
.ajuste-avatar {
	width: 5rem; height: 5rem; border-radius: 50%; object-fit: cover; flex-shrink: 0; display: block;
	border: 2px solid var(--line);
}
.ajuste-avatar--inicial {
	display: flex; align-items: center; justify-content: center; border: 0;
	background: var(--accent); color: var(--accent-contrast); font-family: var(--font-display);
}
.ajuste-avatar--inicial .avatar-inicial::first-letter { font-size: 1.8rem; }
.ajuste-datos { flex: 1; min-width: 0; display: grid; gap: 0.4rem; }
.ajuste-dos { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.6rem 0.7rem; }
.ajuste-guardar { justify-self: start; }
.ajuste-fila { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.ajuste-fila--persona { justify-content: flex-start; gap: 1.2rem; }
.ajuste-fila-texto { flex: 1; min-width: 0; }
.ajuste-plan { margin: 0.3rem 0 0; font-family: var(--font-display); font-size: 1.3rem; }
.ajuste-boton { flex-shrink: 0; white-space: nowrap; }
.ajuste-probar { margin-top: 0.8rem; }
.ajuste-pie-centrado { margin: 0.5rem 0 0; text-align: center; }
.ajuste-texto-premium { margin: 0.6rem 0 0; color: inherit; opacity: 0.9; }
.ajuste-renueva { margin: 0.4rem 0 0; font-size: 0.85rem; opacity: 0.9; }
.ajuste-texto-debajo { margin: 0.6rem 0 0; }
.ajuste-titulo { margin: 0 0 0.3rem; }
.ajuste-titulo--solo { margin-bottom: 0.8rem; }
.ajuste-texto { margin: 0 0 0.8rem; }
.ajuste-texto--tras-titulo { margin-top: 0.3rem; }
.ajuste-campos { display: grid; gap: 0.75rem; }
.ajuste-campo { display: grid; gap: 0.3rem; font-size: 0.82rem; min-width: 0; }
.ajuste-campo--separado { margin-top: 1rem; }
.ajuste-campo-nombre { color: var(--text); font-weight: 700; }
.ajuste-color { display: flex; align-items: center; gap: 0.6rem; }
.ajuste-color-muestra {
	width: 2.6rem; height: 2.2rem; padding: 0.1rem; cursor: pointer;
	border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.ajuste-estado { margin: 0.3rem 0 0; }
.ajuste-opciones { margin-bottom: 0.6rem; }
.ajuste-area { width: 100%; box-sizing: border-box; resize: vertical; }
.ajuste-acciones { margin-top: 0.6rem; }
.ajuste-salir { margin-top: 1.4rem; }
.ajuste-nombre { margin: 0; font-weight: 600; font-size: 1.1rem; }
.ajuste-cita { margin: 0 0 0.9rem; font-size: 0.95rem; }
.objetivo-card--logrado .fact-label { color: inherit; opacity: 0.85; }
/* Lo que se mantiene pulsado (una foto del álbum) no se selecciona. */
.fotos-grid-item.ver-album-foto { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }

/* Hojas: dos altos con nombre, el título que se corta, el cuerpo en lista, el pie a la derecha. */
.sheet-panel.sheet-panel--corta { height: auto; max-height: 70vh; }
.sheet-panel.sheet-panel--media { height: auto; max-height: 80vh; }
.sheet-titulo-cortado { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sheet-body.sheet-body--lista { display: grid; gap: 0.6rem; }
.sheet-footer.sheet-footer--derecha { justify-content: flex-end; gap: 0.6rem; }
.status--chat { margin: 0.3rem 0 0; font-size: 0.8rem; }

/* El coach. */
.card.coach-premium {
	display: block; padding: 1rem 1.2rem; margin-bottom: 0.9rem; text-decoration: none; color: inherit;
	border: 1.5px solid var(--accent);
}
.coach-premium-titulo { display: block; margin-top: 0.2rem; }
.coach-premium-texto { display: block; margin: 0.3rem 0 0; font-size: 0.85rem; }
.coach-parrafo { margin: 0.6rem 0 0; }
.coach-parrafo-nota { margin: 0.5rem 0 0; }
.coach-boton { margin: 0.8rem 0 0; }
.coach-apartado { font-size: 0.95rem; margin: 1rem 0 0.3rem; }
.coach-escrito { margin-top: 1.2rem; }
.coach-rehacer { margin: 0.4rem 0 0; }
.coach-avisos { margin-bottom: 0.9rem; }
.coach-pista { margin: 0 0 0.2rem; font-size: 0.85rem; }
.coach-calendario { margin-top: 0.6rem; }
.mes-nav.coach-mes { margin: 0 0 0.5rem; }
.coach-mes-nombre { font-size: 0.95rem; text-transform: capitalize; }
.coach-dots { display: flex; justify-content: center; }
.card.coach-con-escribir { padding: 1rem 1.2rem; margin-top: 0.7rem; }
.coach-cab { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.6rem; }
.coach-cab-titulo { font-size: 1rem; margin: 0; }
.coach-saldo { flex-shrink: 0; display: flex; align-items: center; gap: 0.4rem; white-space: nowrap; }
.saldo-badge.saldo-badge--llano { background: none; color: var(--accent-text); }
.coach-sesion-cab { margin: 0 0 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
.coach-sesion-titulo { flex: 1; min-width: 0; }
.terapia-quien { display: block; margin-bottom: 0.15rem; }
.consejo-ejercicio { margin: 0; font-weight: 600; }
.consejo-texto { margin: 0.4rem 0 0; line-height: 1.7; }

/* Avisos. */
.avisos-cuenta { margin: 0.4rem 0 0; }
.avisos-vistas { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.9rem; }
.avisos-leer-todo { margin-left: auto; }
.avisos-vacio { margin-top: 1.5rem; }

/* El chat. */
.chat-sin-titulo { font-size: clamp(1.6rem, 4vw, 2.2rem); margin: 0.2rem 0 0; }
.chat-sin-texto { margin-top: 1rem; }
.chat-panel-icono--archivo { background: #7C6BAF; }
.chat-panel-icono--encuesta { background: #2F8F5B; }
.chat-panel-icono--ubicacion { background: #2E6FD4; }
.encuesta-opciones { display: grid; gap: 0.4rem; margin-top: 0.5rem; }
.encuesta-mas { margin-top: 0.5rem; }
.foto-previa-img {
	width: 100%; max-height: 45vh; object-fit: contain; border-radius: var(--radius-sm); background: var(--tint);
}

/* En el móvil, el título de una sección no se come los botones de la cabecera ("Coach de p…"). */
@media (max-width: 30rem) { .topbar h1.topbar-titulo { font-size: 1.05rem; letter-spacing: -0.01em; } }
/* La muestra de color no es un campo de texto: no se estira a lo ancho como los demás. */
.form .ajuste-color .ajuste-color-muestra { width: 2.6rem; flex: 0 0 2.6rem; min-height: 0; }
/* Dos campos en fila: los cuadros a la misma altura aunque una etiqueta ocupe más. */
.ajuste-dos { align-items: end; }
.ajuste-dos > input, .ajuste-dos input { min-width: 0; width: 100%; box-sizing: border-box; }
/* El correo largo se parte en vez de salirse de la tarjeta en un móvil. */
.ajuste-datos .visit-line { overflow-wrap: anywhere; }

/* EN EL ESCRITORIO, sin panel de chat (1100–1399px): el chat a pantalla completa es una
   columna de lectura centrada, no un hilo de 1.400 píxeles con las burbujas en los bordes. */
@media (min-width: 1100px) {
	body.chat-hoja:not(.chat-en-panel) > main > .wrap,
	body.chat-hoja:not(.chat-en-panel) > .chat-pie { max-width: 52rem; margin-left: auto; margin-right: auto; }
	/* Mi cuenta, a dos columnas de campos donde caben (los datos no se leen de corrido). */
	.card.ajuste { padding: 1.3rem 1.6rem; }
}

/* ═══ SOBRE EL ROJO, BLANCO (Rafa, 2026-10-01: "cada texto o icono encima de este fondo rojo
   debe ser blanco") ═══════════════════════════════════════════════════════════════════════
   Es el `sobreAcento` de Tema.swift, y es UNA regla para toda la web: todo lo que se rellena
   de acento —botón primario, chip o pestaña elegida, insignia, la gota del mapa— lleva el
   texto y el trazo en blanco, en claro y en oscuro. Iba repartido por cada componente, y bastaba
   una clase de más para perderlo: los "Sin leer / Todas" de Avisos llevan `.enlace-llano`
   (color: inherit) y se quedaban con la tinta negra encima del rojo.
   Con !important a propósito: es lo que NO puede elegir ninguna pantalla. */
:root { --sobre-acento: #FFFFFF; }
.button--accent, .button--accent:hover, .button--accent:visited, .button--accent:focus,
.chip.is-selected, .chip.is-active, .filtro-btn.is-active, .tab-btn.is-active, .subtab-btn.is-active,
.subnav-tab.is-active, .paga-btn.is-active, .reto-opcion.is-active, .chat-stickers-grupo.is-active,
.buscar-favoritos.is-selected, .tipovalor-btn.is-active, .rank-badge, .mapa-pin-gota,
.listado-puesto, .listado-orden-btn.is-active { color: var(--sobre-acento) !important; }
/* El puesto de una lista va en un disco del acento, como `PuestoEnRanking` en iOS. */
.rank-badge { background: var(--accent); }
:is(.button--accent, .chip.is-selected, .chip.is-active, .filtro-btn.is-active, .tab-btn.is-active,
	.subtab-btn.is-active, .subnav-tab.is-active, .paga-btn.is-active, .reto-opcion.is-active,
	.chat-stickers-grupo.is-active, .buscar-favoritos.is-selected, .tipovalor-btn.is-active,
	.mapa-pin-gota, .listado-orden-btn.is-active)
	:is([data-ico], [data-emoji-icono], .ico, .ico-chip, .ico-suelto, .chip-num, span, strong, small) { color: inherit !important; }
/* La gota del punto NUEVO del mapa es hueca (fondo claro): esa sigue con el trazo rojo. */
.mapa-pin--nuevo .mapa-pin-gota { color: var(--accent-text) !important; }

/* ═══ LA FICHA DE CADA UNO, en Mi cuenta: filas que abren su lista (/ficha) ═══════════════ */
.ficha-filas { padding: 0.3rem 0 !important; }
.ficha-fila {
	display: flex; align-items: center; gap: 0.8rem; padding: 0.75rem 1.1rem;
	color: var(--text); text-decoration: none;
}
.ficha-fila + .ficha-fila { border-top: 1px solid var(--line); }
.ficha-fila:hover { background: var(--tint); }
.ficha-fila-texto { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.ficha-fila-texto strong { font-weight: 600; }
.ficha-fila-texto small { color: var(--muted); font-size: var(--txt-s); }
.ficha-volver { display: inline-flex; align-items: center; gap: 0.2rem; margin: 0.6rem 0 0.4rem; color: var(--accent-text); text-decoration: none; font-weight: 600; font-size: var(--txt-s); }
/* Una lista de PALABRAS: el puesto delante y sin foto (como `sinImagen` en iOS). */
.rank-item--palabra { grid-template-columns: auto 1fr auto; }

/* ═══ EL LISTADO (partials/listado.html + montarListado): Películas, Comidas, Música, Podcasts
   y Lecturas con UNA cara, la de `Listado.swift`. Cambiar aquí cambia las cinco. ═══════════ */
.wrap--listado { max-width: var(--ancho-module); }
.listado-cargando { margin-top: 1rem; }
.listado-pegar { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.8rem; padding: 0.6rem; }
.listado-pegar input { flex: 1; min-width: 0; }
.listado-cabecera { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.8rem; }
.listado-buscar {
	flex: 1; min-width: 0; display: flex; align-items: center; gap: 0.45rem;
	padding: 0 0.8rem; height: 2.5rem; border-radius: 999px;
	background: var(--surface); border: 1px solid var(--line); color: var(--muted);
}
.listado-buscar input { flex: 1; min-width: 0; border: 0 !important; background: none !important; box-shadow: none !important; padding: 0 !important; outline: none; color: var(--text); font: inherit; }
.listado-mas { width: 2.5rem; height: 2.5rem; padding: 0 !important; border-radius: 50% !important; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.listado-seccion { margin: 1.3rem 0 0.5rem; font-size: 1.05rem; }
.listado-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.6rem; }
.listado-chip { display: inline-flex; align-items: center; gap: 0.15rem; font-size: var(--txt-s); }
.listado-ordenar { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 0.6rem; flex-wrap: wrap; }
.listado-ordenar .visit-line { margin: 0; font-size: var(--txt-s); }
.listado-lista { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.listado-tarjeta {
	display: flex; align-items: center; gap: 0.75rem; padding: 0.6rem 0.7rem;
	width: 100%; text-align: left; cursor: pointer; color: var(--text); font: inherit;
}
.listado-imagen {
	position: relative; width: 56px; height: 56px; flex: 0 0 56px; border-radius: 8px; overflow: visible;
	background: var(--accent-soft); color: var(--accent-text); display: flex; align-items: center; justify-content: center;
}
.listado-imagen img { width: 56px; height: 56px; border-radius: 8px; object-fit: cover; display: block; }
/* EL PUESTO en el ranking, en su disco del acento colgando de la esquina de la miniatura. */
.listado-puesto {
	position: absolute; top: -6px; left: -6px; min-width: 22px; height: 22px; padding: 0 5px;
	border-radius: 999px; background: var(--accent); color: var(--sobre-acento);
	font-size: 0.72rem; font-weight: 700; display: flex; align-items: center; justify-content: center;
	box-shadow: 0 0 0 2px var(--surface);
}
.listado-textos { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.listado-titulo { font-weight: 600; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.listado-sub { color: var(--muted); font-size: var(--txt-s); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.listado-detalle { display: flex; align-items: center; gap: 0.4rem; color: var(--muted); font-size: var(--txt-xs); white-space: nowrap; overflow: hidden; }
.listado-detalle .tag-chip { flex-shrink: 0; }
.listado-candado { display: inline-flex; align-items: center; gap: 0.15rem; color: var(--accent-text); }
/* LA ★ TUYA: hueca, y rellena del acento si es favorita tuya. Siempre en el mismo sitio. */
.listado-estrella {
	flex-shrink: 0; width: 2.4rem; height: 2.4rem; border-radius: 50%; border: 0; background: none;
	color: var(--muted); display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.listado-estrella:hover { background: var(--tint); }
.listado-estrella.is-on { color: var(--accent); }
.listado-estrella.is-on svg { fill: currentColor; }
.listado-asa { flex-shrink: 0; color: var(--muted); cursor: grab; display: inline-flex; }
.listado-lista.is-ordenando .listado-tarjeta { cursor: grab; }
.listado-fila.is-cogida { opacity: 0.45; }
.listado-vacio { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.4rem; padding: 2rem 1rem; color: var(--accent-text); }
.listado-vacio strong { color: var(--text); }
.listado-vacio .visit-line { margin: 0; max-width: 26rem; }
.listado-resultado { gap: 0.6rem; }
.listado-resultado > .ico-suelto { color: var(--accent-text); flex-shrink: 0; }
.listado-ficha-imagen { width: 100%; max-height: 18rem; object-fit: contain; border-radius: var(--radius-sm); background: var(--tint); margin-bottom: 0.6rem; }
.listado-ficha-texto { white-space: pre-wrap; line-height: 1.5; }
.listado-ficha-seccion { margin: 0.9rem 0 0.35rem; }
.listado-ficha-estados, .listado-ficha-donde { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.listado-ficha-donde a { text-decoration: none; }
.listado-credito { margin-top: 1.2rem; font-size: var(--txt-xs); }

/* ═══ CUARTA PASADA DEL ESCRITORIO (2026-10-01): LA MISMA CARCASA EN TODAS ═════════════════ */

/* EL "+" DE AÑADIR EN LÍNEA (Tareas, Gastos): un redondo del alto del campo, como el "+" de
   la cabecera y el del listado. Era un rectangulito más bajo que los campos y descolgado. */
#tareaForm > button[type="submit"], #gastoForm > button[type="submit"] {
	width: 2.6rem; height: 2.6rem; min-height: 0; padding: 0 !important; border-radius: 50%;
	display: inline-flex; align-items: center; justify-content: center; font-size: 1.25rem; line-height: 1;
}

/* AVISOS: las dos filas de arriba con la misma forma. "Sin leer · Todas" eran botones
   cuadrados pequeños y los asuntos píldoras grandes: dos tamaños para la misma clase de cosa. */
.avisos-vistas .button { border-radius: 999px; padding: 0.42rem 0.9rem; font-size: var(--txt-s); }
.avisos-filtros .chip { padding: 0.42rem 0.9rem; font-size: var(--txt-s); }

/* TU COACH es una de las TRES tarjetas del coach: su título y su texto, como los de las otras
   dos (el título de un acordeón y el texto de una tarjeta), no un cartel más grande. */
.card h2.coach-cab-titulo { font-family: inherit; font-size: 1rem; font-weight: 600; letter-spacing: 0; margin: 0; }
p.coach-parrafo, p.coach-parrafo-nota { font-size: 0.9rem; line-height: 1.55; }

/* BUSCAR en Mi cuenta: la palabra a la izquierda, junto a su lupa (salía centrada). */
.fila-buscar > span { text-align: left; }

/* LA CABECERA DE ESCRITORIO de un LISTADO (app.js sube ahí el buscador y el "+"): mismas
   medidas que la de las demás pantallas, sin lo que la caja traía de cuando iba debajo. */
@media (min-width: 1100px) {
	.topbar .listado-cabecera { margin: 0 0 0 auto; }
	.topbar .listado-buscar { flex: 0 1 auto; height: 2.4rem; }
	.topbar .listado-mas { width: 2.4rem; height: 2.4rem; }
	/* El TÍTULO no se recorta ("Gastos comparti…"): lo que cede sitio es el buscador. */
	.topbar-titulo { flex-shrink: 0; }
	.topbar-buscar { min-width: 0; }
	.topbar-buscar input { width: clamp(6rem, 14vw, 13rem); }
	/* EVENTOS: su "+ Nuevo" ya es el "+" de la cabecera (HERRAMIENTAS lo pulsa); dos botones
	   rojos de añadir en la misma pantalla eran uno de más. */
	.topbar-herramientas ~ * .anadir-calendario, body:has(.topbar-herramientas .topbar-mas) main .anadir-calendario { display: none; }
}

/* UNA HOJA ENCIMA DEL DÍA (el evento, abierto desde el panel del día): un diálogo centrado
   como todas. Heredaba del panel del día —que baja desde arriba— el "fijo a los cuatro
   bordes", y salía pegada a la esquina de arriba a la izquierda, tapando la columna a medias. */
@media (min-width: 1100px) and (hover: hover) and (pointer: fine) {
	.sheet-overlay--arriba .sheet-overlay > .sheet-panel {
		position: relative; inset: auto; transform: none; margin: 0;
		width: 100%; max-width: 38rem; height: auto; max-height: min(86vh, 56rem);
		border-radius: var(--radius);
	}
}

/* ═══ EVENTOS: la lista, las carpetas y la ficha (2026-10-02) ═══════════════════════════════
   PlanesView, CarpetaDeCategoria y PlanView de iOS. Las piezas son las de siempre (la carcasa
   de listado, las hojas, los chips de enlace); aquí solo lo que es suyo. */

/* EL CONMUTADOR "Eventos | Categorías": el segmentado de iOS. En el móvil, a lo ancho. */
.conmutador { display: inline-flex; padding: 3px; gap: 2px; border-radius: 999px; background: var(--tint); margin: 0.9rem 0 0.2rem; }
.conmutador button {
	border: 0; background: none; padding: 0.42rem 1.15rem; border-radius: 999px; cursor: pointer;
	font: inherit; font-weight: 600; font-size: var(--txt-s); color: var(--muted);
}
.conmutador button.is-on { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }
@media (max-width: 1099px) { .conmutador { display: flex; } .conmutador button { flex: 1; } }

/* La línea de CUÁNDO de una fila de evento, en rojo (LineaDeCuandoYDonde). */
.listado-cuando { color: var(--accent-text); font-size: var(--txt-s); font-weight: 600; }
/* Mirando una categoría: su nombre, sus fotos y la X para volver a todos. */
.listado-barra-cat {
	display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.6rem 0.5rem 0.85rem; margin: 0 0 0.7rem;
	border-radius: var(--radius-sm); background: var(--tint); color: var(--accent-text);
}
.listado-barra-cat strong { color: var(--text); }
.listado-barra-cat-fotos { margin-left: auto; font-weight: 600; font-size: var(--txt-s); color: var(--accent-text); }
.listado-barra-cat .boton-icono { color: var(--muted); }

/* LAS CARPETAS (CarpetaDeCategoria): portada, nombre con su trazo y "N eventos · M fotos";
   apagada si no tiene nada. */
.carpetas { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: 1.1rem 0.9rem; }
.carpeta {
	display: flex; flex-direction: column; gap: 0.2rem; padding: 0; border: 0; background: none;
	text-align: left; cursor: pointer; font: inherit; color: var(--text); min-width: 0;
}
.carpeta-portada {
	display: flex; align-items: center; justify-content: center; height: 9.4rem; overflow: hidden;
	border-radius: var(--radius-sm); background: var(--accent-soft); color: var(--accent-text);
}
.carpeta-portada img { width: 100%; height: 100%; object-fit: cover; display: block; }
.carpeta:hover .carpeta-portada { filter: brightness(0.96); }
.carpeta-nombre {
	display: flex; align-items: center; gap: 0.3rem; margin-top: 0.25rem; font-weight: 600; font-size: var(--txt-s);
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.carpeta-nombre .ico-suelto { color: var(--accent-text); flex-shrink: 0; }
.carpeta-cuenta { color: var(--muted); font-size: var(--txt-xs); }
.carpeta--vacia { opacity: 0.5; }
@media (max-width: 600px) {
	.carpetas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.carpeta-portada { height: 8.5rem; }
}

/* ── LA FICHA DE UN EVENTO ─────────────────────────────────────────────────────────────── */
.ficha-ev { position: relative; padding: 0; }
.ficha-ev-scroll { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; }
.ficha-ev-cerrar {
	position: absolute; top: 0.8rem; right: 0.8rem; z-index: 3; width: 2.5rem; height: 2.5rem;
	border-radius: 50%; border: 0; cursor: pointer; display: flex; align-items: center; justify-content: center;
	background: rgba(250, 249, 246, 0.88); backdrop-filter: blur(10px); color: #1B1813;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.ficha-ev-portada {
	position: relative; height: 15rem; overflow: hidden;
	display: flex; align-items: center; justify-content: center;
	background: var(--accent-soft); color: var(--accent-text);
}
.ficha-ev-portada img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; cursor: zoom-in; }
.ficha-ev-portada-dibujo { margin-bottom: 3.6rem; }
.ficha-ev-velo { position: absolute; left: 0; right: 0; bottom: 0; padding: 2.4rem 1.4rem 1rem; pointer-events: none; }
.ficha-ev-portada.con-foto .ficha-ev-velo { background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.62)); color: #FFFFFF; }
.ficha-ev-titulo { margin: 0.1rem 0 0; font-family: var(--font-display); font-size: 1.6rem; line-height: 1.15; color: inherit; }
.ficha-ev-portada:not(.con-foto) .ficha-ev-titulo { color: var(--text); }
.ficha-ev-cuando { margin: 0; font-size: var(--txt-s); font-weight: 600; }
.ficha-ev-portada:not(.con-foto) .ficha-ev-cuando { color: var(--accent-text); }
.ficha-ev-pie { margin: 0.25rem 0 0; font-size: var(--txt-xs); opacity: 0.85; }
.ficha-ev-portada:not(.con-foto) .ficha-ev-pie { color: var(--muted); }
/* LOS REDONDOS: disco con su trazo y el nombre debajo; la ★ la primera, borrar el último. */
.ficha-ev-redondos { display: flex; justify-content: center; flex-wrap: wrap; gap: 1.1rem; padding: 1rem 1rem 0.4rem; }
.ficha-ev-redondo {
	display: flex; flex-direction: column; align-items: center; gap: 0.3rem; min-width: 3.6rem;
	border: 0; background: none; padding: 0; cursor: pointer; font: inherit; color: var(--text);
}
.ficha-ev-redondo-disco {
	width: 3rem; height: 3rem; border-radius: 50%; display: flex; align-items: center; justify-content: center;
	background: var(--tint); color: var(--accent-text); transition: filter 0.15s ease;
}
.ficha-ev-redondo:hover .ficha-ev-redondo-disco { filter: brightness(0.94); }
.ficha-ev-redondo-texto { font-size: var(--txt-xs); color: var(--muted); }
.ficha-ev-redondo--estrella.is-on .ficha-ev-redondo-disco svg { fill: currentColor; }
.ficha-ev-redondo--peligro .ficha-ev-redondo-disco { color: var(--bad); }
.ficha-ev-cuerpo { padding: 0.6rem 1.4rem 1.6rem; display: flex; flex-direction: column; gap: 1.3rem; }
.ficha-ev-resumen { display: grid; grid-template-columns: 1fr 1fr; gap: 0.9rem 1.2rem; padding: 1rem 1.1rem; }
.ficha-ev-seccion--ancha { grid-column: 1 / -1; }
.ficha-ev-seccion-titulo { margin: 0 0 0.45rem; }
.ficha-ev-cuando-linea { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.7rem; }
.ficha-ev-cuando-texto { font-weight: 600; }
.ficha-ev-ver-dia { font-size: var(--txt-s); font-weight: 600; color: var(--accent-text); }
.ficha-ev-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.ficha-ev-notas { margin: 0; white-space: pre-wrap; line-height: 1.5; }
.ficha-ev-fotos { flex-wrap: wrap; overflow: visible; }
.ficha-ev-comentarios { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.ficha-ev-com-col { display: flex; flex-direction: column; gap: 0.15rem; max-width: 80%; }
.reto-msg-fila--mia .ficha-ev-com-col { align-items: flex-end; }
.ficha-ev-com-quien { font-size: var(--txt-xs); color: var(--muted); margin-left: 0.4rem; }
.ficha-ev-com-acc { display: flex; gap: 0.1rem; align-self: center; opacity: 0.35; transition: opacity 0.15s ease; }
.ficha-ev-com:hover .ficha-ev-com-acc, .ficha-ev-com-acc:focus-within { opacity: 1; }
.ficha-ev-com-acc .boton-icono { color: var(--muted); }
.ficha-ev-nada { margin: 0 0 0.4rem; }
.ficha-ev-escribir { margin-top: 0.7rem; }
.ficha-ev-cargando, .ficha-ev-fallo { padding: 2rem 1.4rem; }
.ficha-ev-campo { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.8rem; }
.ficha-ev-campos-fila { display: grid; grid-template-columns: 1fr 1fr; gap: 0.8rem; }
@media (max-width: 600px) {
	.ficha-ev-resumen { grid-template-columns: 1fr; }
	.ficha-ev-portada { height: 12.5rem; }
	.ficha-ev-cuerpo { padding: 0.5rem 1rem 1.4rem; }
	.ficha-ev-redondos { gap: 0.7rem; }
}
@media (min-width: 1100px) and (hover: hover) and (pointer: fine) {
	.sheet-overlay.ficha-ev-overlay > .sheet-panel.ficha-ev { max-width: 46rem; max-height: min(90vh, 60rem); }
	.ficha-ev-portada { height: 17rem; }
}

/* EL VISOR: la X de cerrar a la derecha y los tres puntos a la izquierda (su menú se abre
   debajo de ellos). Sin menú, el hueco de los puntos se guarda: la fecha sigue centrada. */
.visor-top-btn#visorMasBtn[hidden] { display: flex !important; visibility: hidden; }
.visor-menu { left: 0.8rem; right: auto; }
/* Los títulos de sección de la ficha son etiquetas (como LUGAR, FOTOS en toda la app): dentro
   de una tarjeta, la regla de los h3 de .card los inflaba. Y "Cuándo" lleva la frase más
   larga: se le da algo más de ancho. En el móvil, los redondos en UNA fila. */
.ficha-ev .ficha-ev-seccion-titulo { font-size: 0.7rem; font-family: inherit; line-height: 1.3; }
.ficha-ev-resumen { grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); }
@media (max-width: 600px) {
	.ficha-ev-resumen { grid-template-columns: 1fr; }
	.ficha-ev-redondos { flex-wrap: nowrap; justify-content: space-between; gap: 0.25rem; padding: 0.9rem 0.8rem 0.3rem; }
	.ficha-ev-redondo { min-width: 0; flex: 1 1 0; }
	.ficha-ev-redondo-texto { font-size: 0.68rem; white-space: nowrap; }
}

/* UNA FOTO QUE YA SOLO ESTÁ EN LOS MÓVILES (ver `huecoParaLaFotoQueSeFue` en app.js): el
   mismo hueco que ocupaba, con el fondo suave de la app y el dibujo de una foto en el centro.
   Nunca el icono roto del navegador. Si el <img> no tenía tamaño propio, se queda en un
   cuadrado discreto. El dibujo va en dos colores porque una imagen de fondo no lee var(--…). */
img.foto-ida {
	background-color: var(--tint);
	background-repeat: no-repeat;
	background-position: center;
	background-size: min(36px, 40%) auto;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2386807A' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='3'/%3E%3Ccircle cx='9' cy='10' r='1.8'/%3E%3Cpath d='m21 16-5-5-9 9'/%3E%3C/svg%3E");
	min-width: 2.5rem;
	min-height: 2.5rem;
	object-fit: cover;
}
@media (prefers-color-scheme: dark) {
	img.foto-ida {
		background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239B948A' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='3'/%3E%3Ccircle cx='9' cy='10' r='1.8'/%3E%3Cpath d='m21 16-5-5-9 9'/%3E%3C/svg%3E");
	}
}

