/* ============================================================
   ForgePublish v2 — tokens (lenguaje visual aprobado el 11/09: fucsia)
   Ningún color fuera de este bloque. Contrastes medidos antes de fijarlos.
   ============================================================ */

/* Tipografías ALOJADAS AQUÍ (descargadas una sola vez el 11/09, licencia OFL).
   Ninguna petición a terceros, y no por promesa: la CSP (font-src 'self') lo impone.
   Son variables: un fichero cubre varios pesos. Solo alfabeto latino
   (incluye á é í ó ú ñ ç l·l € ¿ ¡). */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 600 700;
  font-display: swap;
  src: url("../fonts/bricolage-grotesque-600-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/figtree-400-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  color-scheme: light;

  --lienzo: #F7F6FB;
  --superficie: #FFFFFF;
  --superficie-2: #F1EFF7;
  --divisor: #E4E1EE;
  --borde-campo: #8F8AA3;      /* 3,32:1 */
  --tinta: #16131F;            /* 17,03:1 */
  --tinta-2: #5E5A70;          /* 6,16:1 */

  --primario: #A21CAF;         /* 6,32:1 con texto blanco */
  --primario-hover: #86198F;
  --sobre-primario: #FFFFFF;
  --primario-texto: #A21CAF;   /* 5,88:1 */
  --primario-suave: #FAE8FF;

  --foco: #7C3AED;             /* violeta de casa · 5,30:1 */
  --marca-a: #C026D3;
  --marca-b: #7C3AED;
  --sobre-marca: #FFFFFF;      /* sobre el degradado: 4,71:1 en su extremo más claro */

  --exito: #047857;   --exito-fondo: #ECFDF5;
  --aviso: #B45309;   --aviso-fondo: #FFFBEB;
  --peligro: #B91C1C; --peligro-fondo: #FEF2F2;
  --sobre-peligro: #FFFFFF;

  --sombra: 0 1px 2px rgb(22 19 31 / .06), 0 10px 28px rgb(22 19 31 / .08);
  --radio-m: 14px;
  --radio-pill: 999px;

  /* Las tipografías se alojarán aquí mismo; hasta entonces, las del sistema. */
  --f-titulo: "Bricolage Grotesque", "Figtree", system-ui, sans-serif;
  --f-ui: "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --f-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Menlo, monospace;

  --t-xs: .75rem;
  --t-s: .875rem;
  --t-m: 1rem;
  --t-l: 1.25rem;
  --t-xl: 1.625rem;
  --t-2xl: 2.25rem;

  --tactil: 44px;
}

/* Oscuro: por el ajuste del sistema, salvo que la persona fije «claro».
   Solo en PANTALLA (`screen`): el papel va siempre en claro, lo fuerce o no
   el navegador al imprimir (10b·3). */
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-tema="claro"]) {
    color-scheme: dark;
    --lienzo:#0F0E14; --superficie:#181622; --superficie-2:#211E2D; --divisor:#2A2638; --borde-campo:#6E6882;
    --tinta:#F4F2F9; --tinta-2:#ABA6BD;
    --primario:#E879F9; --primario-hover:#F0ABFC; --sobre-primario:#16131F; --primario-texto:#F0ABFC; --primario-suave:#3B1740;
    --foco:#A78BFA;
    --exito:#34D399; --exito-fondo:#0E2A21; --aviso:#FBBF24; --aviso-fondo:#2E2208; --peligro:#F87171; --peligro-fondo:#33141A; --sobre-peligro:#16131F;
    --sombra: 0 1px 2px rgb(0 0 0 / .45), 0 10px 28px rgb(0 0 0 / .35);
  }
}
/* …y «oscuro» fijado a mano gana siempre (el interruptor llegará con el perfil);
   también solo en pantalla. */
@media screen {
:root[data-tema="oscuro"] {
  color-scheme: dark;
  --lienzo:#0F0E14; --superficie:#181622; --superficie-2:#211E2D; --divisor:#2A2638; --borde-campo:#6E6882;
  --tinta:#F4F2F9; --tinta-2:#ABA6BD;
  --primario:#E879F9; --primario-hover:#F0ABFC; --sobre-primario:#16131F; --primario-texto:#F0ABFC; --primario-suave:#3B1740;
  --foco:#A78BFA;
  --exito:#34D399; --exito-fondo:#0E2A21; --aviso:#FBBF24; --aviso-fondo:#2E2208; --peligro:#F87171; --peligro-fondo:#33141A; --sobre-peligro:#16131F;
  --sombra: 0 1px 2px rgb(0 0 0 / .45), 0 10px 28px rgb(0 0 0 / .35);
}
}

/* ============================================================
   Base
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--lienzo);
  color: var(--tinta);
  font-family: var(--f-ui);
  font-size: var(--t-m);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
:focus-visible { outline: 3px solid var(--foco); outline-offset: 2px; }
h1, h2, h3 { margin: 0; font-family: var(--f-titulo); line-height: 1.12; letter-spacing: -.015em; text-wrap: balance; }
h1 { font-size: var(--t-xl); font-weight: 700; }
p { margin: 0; max-width: 65ch; }
a { color: var(--primario-texto); }
.etiqueta { font-family: var(--f-ui); font-size: var(--t-xs); font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--tinta-2); }
.secundario { color: var(--tinta-2); }

/* ============================================================
   Componentes
   ============================================================ */
.lamina { background: var(--superficie); border: 1px solid var(--divisor); border-radius: var(--radio-m); box-shadow: var(--sombra); padding: 24px 20px; }

.sello {
  flex: none; width: 36px; height: 36px; border-radius: 10px;
  display: grid; place-items: center;
  background: linear-gradient(135deg, var(--marca-a), var(--marca-b));
  color: var(--sobre-marca); font-family: var(--f-titulo); font-weight: 700;
}

/* El relleno vertical y el interlineado son para las etiquetas de DOS líneas,
   que a 320 aparecen en cuanto la etiqueta dice algo entero («Dejar de
   publicar sin enseñárselo»): con `/1` y sin relleno, las dos líneas medían
   42 px dentro de 44 y los acentos rozaban el borde. Los botones de UNA línea
   no se mueven: 16 + 16 = 32 px, por debajo del mínimo táctil, que sigue
   mandando. */
.btn {
  min-height: var(--tactil); padding: 8px 18px; border-radius: var(--radio-pill);
  border: 1px solid transparent; font: 600 var(--t-m)/1.2 var(--f-ui); cursor: pointer; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: background-color .15s ease, border-color .15s ease;
}
.btn--principal { background: var(--primario); color: var(--sobre-primario); }
.btn--principal:hover { background: var(--primario-hover); }
.btn--secundario { background: var(--superficie); color: var(--tinta); border-color: var(--borde-campo); }
.btn--secundario:hover { background: var(--superficie-2); }
.btn--ancho { width: 100%; }

.formulario { display: grid; gap: 18px; }
.campo { display: grid; gap: 6px; }
.campo label { font-weight: 600; font-size: var(--t-s); }
.campo input, .campo select, .campo textarea {
  min-height: var(--tactil); width: 100%; padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--borde-campo); background: var(--superficie); color: var(--tinta);
  font: 400 var(--t-m)/1.2 var(--f-ui);
}
/* 5b2: un texto largo (la voz, qué se cuenta en un tema). Con relleno arriba
   y abajo, interlineado de lectura, y que crezca hacia abajo, nunca a lo ancho. */
.campo textarea { padding: 10px 12px; line-height: 1.5; resize: vertical; }

/* max-width: none — un aviso es un <p> y heredaba el tope de 65ch de los
   párrafos: en escritorio quedaba más estrecho que la lista de debajo. En
   el móvil no se notaba; lo vio Joaquim en su pantalla. */
.aviso { max-width: none; background: var(--primario-suave); color: var(--primario-texto); border-radius: 10px; padding: 12px 14px; font-size: var(--t-s); font-weight: 600; }

/* ── Acceso: entrar y errores ─────────────────────────────── */
.acceso { min-height: 100dvh; display: grid; align-content: center; justify-items: center; gap: 20px; padding: 32px 16px; }
.acceso__marca { display: flex; align-items: center; gap: 10px; }
.acceso__nombre { font-family: var(--f-titulo); font-weight: 700; font-size: var(--t-l); }
.acceso__caja { width: 100%; max-width: 400px; display: grid; gap: 18px; }
.acceso__pie { font-size: var(--t-s); color: var(--tinta-2); text-align: center; max-width: 34ch; }

/* ── Avisos con intención ─────────────────────────────────────
   entrar.php ya usaba .aviso--error en 4a y la clase NO existía: el error
   salía en fucsia. Se midió el contraste del rojo y se pintaba otra cosa. */
.aviso--error { background: var(--peligro-fondo); color: var(--peligro); }
.aviso--ok { background: var(--exito-fondo); color: var(--exito); }

form { margin: 0; }
h2 { font-size: var(--t-l); font-weight: 700; }
.ayuda { font-size: var(--t-s); color: var(--tinta-2); }
.fuerte { color: var(--tinta); font-weight: 600; }
.pila { display: grid; gap: 14px; }

/* Un grupo de la agenda del Inicio: su título, su lista y su nota, JUNTOS.
   `.pila` reparte 14px a todo por igual, y con eso la nota de una semana se
   leía como la entradilla de la lista de la SIGUIENTE (lo vio Joaquim en vivo
   el 04/10). Dentro de la caja se aprieta a 6px: lo de dentro va junto y los
   14px de `.pila` quedan para separar un grupo del otro. La proximidad es la
   que dice qué va con qué — no hay color ni línea nuevos. */
.agenda-grupo { display: grid; gap: 6px; }
/* Y un poco más de aire ENTRE grupos, que es donde tiene que estar el corte:
   6px dentro contra 20px fuera se ve a la primera, también a 320. */
.agenda-grupo + .agenda-grupo { margin-top: 6px; }

/* ── La app: barra de arriba ──────────────────────────────── */
.barra {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; background: var(--superficie); border-bottom: 1px solid var(--divisor);
}
/* text-decoration: none — el logo es un enlace y heredaba el subrayado: la
   «F» salía subrayada. Ninguna medida lo vio; lo vio la captura. */
/* min-width/min-height (5a): el sello mide 36 px y el enlace medía lo mismo,
   por debajo de los 44 px de zona táctil. Desde 4a; lo cazó la medida de 5a,
   que por primera vez recorrió TODOS los enlaces y no solo los del formulario.
   El sello se ve igual: crece la zona que se puede tocar, no el dibujo. */
.barra__marca { display: inline-flex; align-items: center; justify-content: center; min-width: var(--tactil); min-height: var(--tactil); border-radius: 10px; text-decoration: none; }
/* MÓVIL PRIMERO: la navegación va ABAJO, al alcance del pulgar, en columnas
   iguales. Con Semana, Clientes y Equipo más Salir, arriba no cabía a 375 px.
   Arriba quedan el logo y Salir, cada uno en su extremo. */
.barra { justify-content: space-between; }
.barra__nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px;
  padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
  background: var(--superficie); border-top: 1px solid var(--divisor);
}
/* Que la barra de abajo no tape el final de la página. */
.barra ~ .pagina { padding-bottom: calc(var(--tactil) + 72px); }

@media (min-width: 640px) {
  .barra { justify-content: flex-start; }
  .barra__nav {
    position: static; flex: 1 1 0; min-width: 0;
    display: flex; gap: 4px; padding: 0; background: transparent; border-top: 0;
  }
  .barra ~ .pagina { padding-bottom: 48px; }
}
.barra__enlace {
  flex: none; min-height: var(--tactil); display: inline-flex; align-items: center;
  padding: 0 12px; border-radius: var(--radio-pill);
  color: var(--tinta-2); font-weight: 600; text-decoration: none;
}
.barra__enlace:hover { background: var(--superficie-2); color: var(--tinta); }
.barra__enlace[aria-current="page"] { background: var(--primario-suave); color: var(--primario-texto); }

.btn--fantasma { background: transparent; color: var(--tinta-2); padding: 0 12px; }
.btn--fantasma:hover { background: var(--superficie-2); color: var(--tinta); }
.btn--peligro { background: var(--peligro); color: var(--sobre-peligro); }
.btn--peligro:hover { filter: brightness(.92); }
.btn--peligro-suave { background: var(--superficie); color: var(--peligro); border-color: var(--peligro); }
.btn--peligro-suave:hover { background: var(--peligro-fondo); }

/* ── Páginas ──────────────────────────────────────────────── */
.pagina { width: 100%; max-width: 760px; margin: 0 auto; padding: 20px 16px 48px; display: grid; gap: 16px; }
.pagina--estrecha { max-width: 520px; }
.pagina__cabeza { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.volver { justify-self: start; min-height: var(--tactil); display: inline-flex; align-items: center; font-weight: 600; text-decoration: none; }
/* La semana anterior y la siguiente (9a-ter). `minmax(0, 1fr)` y no `1fr`: con
   `1fr` la columna no baja del CONTENIDO del botón, y a 320 el par se saldría
   en vez de repartirse. Son dos, siempre: por eso dos columnas y no un flex. */
.semanas { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }

/* ── Listas de filas (equipo, y lo que venga) ─────────────── */
.lista {
  list-style: none; margin: 0; padding: 0;
  background: var(--superficie); border: 1px solid var(--divisor); border-radius: var(--radio-m);
  box-shadow: var(--sombra); overflow: hidden;
}
.lista > li + li { border-top: 1px solid var(--divisor); }
.fila { display: flex; align-items: center; gap: 12px; min-height: 64px; padding: 10px 16px; color: var(--tinta); text-decoration: none; }
/* Solo cambia al pasar por encima si la fila ES un enlace: una fila que no
   lleva a ningún sitio y se ilumina promete un clic que no existe. */
a.fila:hover { background: var(--superficie-2); }
/* flex: 1 1 0 y min-width: 0, NO auto: con auto, un correo largo empuja el
   estado fuera de la fila en vez de cortarse con puntos suspensivos. */
.fila__datos { flex: 1 1 0; min-width: 0; display: grid; }
.fila__titulo { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fila__sub { font-size: var(--t-s); color: var(--tinta-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.inicial {
  flex: none; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--primario-suave); color: var(--primario-texto);
  font-family: var(--f-titulo); font-weight: 700;
}
.inicial--grande { width: 56px; height: 56px; font-size: var(--t-l); }

.estado { flex: none; font-size: var(--t-xs); font-weight: 700; padding: 4px 10px; border-radius: var(--radio-pill); white-space: nowrap; }
.estado--activa { background: var(--exito-fondo); color: var(--exito); }
.estado--pendiente { background: var(--aviso-fondo); color: var(--aviso); }
.estado--desactivada { background: var(--superficie-2); color: var(--tinta-2); }

/* ── Ficha ────────────────────────────────────────────────── */
.ficha { display: flex; align-items: center; gap: 14px; }
.ficha__datos { min-width: 0; }
.ficha__datos p { overflow-wrap: anywhere; }
.datos { margin: 0; display: grid; gap: 10px; }
.datos > div { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.datos dt { color: var(--tinta-2); }
.datos dd { margin: 0; text-align: right; font-weight: 600; }
.campo-copia { background: var(--superficie-2); font: 500 var(--t-s)/1.2 var(--f-mono); }
/* 9c · Un mensaje preparado se copia igual que un enlace, pero se LEE como
   texto corrido: letra de interfaz y aire de párrafo, no mono. */
textarea.campo-copia { font: 500 var(--t-s)/1.5 var(--f-ui); }
/* El mensaje se lee ENTERO antes de mandarlo: el enlace va al final, y un
   campo con barra de scroll lo esconde justo a él. Crece hasta su texto
   donde el navegador sabe; donde no, el `rows` de la pantalla es la reserva. */
textarea.campo-copia[readonly] { field-sizing: content; resize: none; }
.enlace-listo { border-color: var(--primario); }
.confirmar { border-color: var(--peligro); }

/* ── Detalles de la barra ─────────────────────────────────── */
.barra__enlace { justify-content: center; }

/* ── Oculto de verdad, y oculto solo a la vista ───────────── */
/* !important: si una clase pone display (el ojo usa grid), el atributo
   hidden dejaría de ocultar y aparecería un botón que no hace nada. */
[hidden] { display: none !important; }
.solo-lector {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── Lo que pide atención ─────────────────────────────────── */
.aviso--atencion { background: var(--aviso-fondo); color: var(--aviso); }
.estado--atencion { background: var(--aviso-fondo); color: var(--aviso); }
.fila__sub--libre { white-space: normal; }
/* 9e2 · f · La ÚNICA línea de la agenda que es una alarma (el automatismo del
   silencio puede estar parado). Con la misma pareja que los avisos de arriba
   —el color solo, sobre el gris de una fila iluminada, no llega a AA—, y con
   su peso. Solo tan ancha como su texto, con aire para no pegarse a la línea
   del 9d, que es un enlace. */
.fila__sub--atencion {
  background: var(--aviso-fondo); color: var(--aviso); font-weight: 600;
  justify-self: start; padding: 6px 10px; border-radius: 10px; margin-block: 4px;
}

/* ── El ojo de la contraseña ──────────────────────────────── */
/* El botón ocupa el alto ENTERO del campo: queda centrado por construcción,
   no por un número. En v1 se colocó a ojo y salía 24 px por debajo. */
.campo-clave { position: relative; }
.campo-clave input { padding-right: calc(var(--tactil) + 4px); }
.campo-clave input::-ms-reveal { display: none; }   /* Edge pone su propio ojo: dos ojos confunden */
.ojo {
  position: absolute; top: 0; right: 0; width: var(--tactil); height: 100%;
  display: grid; place-items: center; padding: 0; border: 0; border-radius: 10px;
  background: transparent; color: var(--tinta-2); cursor: pointer;
}
.ojo:hover { color: var(--tinta); }
.ojo svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ojo__cerrado { display: none; }
.ojo[aria-pressed="true"] .ojo__abierto { display: none; }
.ojo[aria-pressed="true"] .ojo__cerrado { display: block; }

/* ── Elegir clientes ──────────────────────────────────────── */
.eleccion { margin: 0; padding: 0; border: 1px solid var(--divisor); border-radius: var(--radio-m); overflow: hidden; }
.opcion { display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 8px 16px; cursor: pointer; }
.opcion + .opcion { border-top: 1px solid var(--divisor); }
/* 5b2: si la primera opción está oculta (el idioma principal), la siguiente
   pasa a ser la primera y no lleva línea arriba: se vería una raya doble. */
.opcion[hidden] + .opcion { border-top: 0; }
.opcion:hover { background: var(--superficie-2); }
.opcion input { flex: none; width: 22px; height: 22px; margin: 0; accent-color: var(--primario); }
.opcion input:disabled + span { color: var(--tinta-2); }
.etiquetas { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.etiqueta-cliente {
  background: var(--superficie-2); color: var(--tinta); border-radius: var(--radio-pill);
  padding: 6px 12px; font-size: var(--t-s); font-weight: 600;
}

/* ============================================================
   5a · El alta de un cliente y su ficha
   ============================================================ */

/* Una etiqueta pequeña encima de un título, pegada a él. */
.titular { display: grid; gap: 4px; }

/* Un nombre de cliente largo en «← volver» o en el título no puede empujar
   la página hacia los lados a 320 px. */
.volver { max-width: 100%; overflow-wrap: anywhere; }
.ficha__datos h1 { overflow-wrap: anywhere; }

/* ── Formularios largos: grupos, opciones plegadas y errores ── */
/* min-width: 0 — un fieldset tiene min-width: min-content por defecto, y un
   valor largo dentro lo ensancharía más que la pantalla. */
.grupo { margin: 0; padding: 0; border: 0; min-width: 0; display: grid; gap: 14px; }
.grupo > legend { padding: 0; margin-bottom: 14px; font-family: var(--f-titulo); font-weight: 700; font-size: var(--t-l); line-height: 1.12; }
/* 5d: un campo que es una pregunta más entre grupos («¿Cuántos?» entre «¿Qué
   se ha contratado?» y «¿Cada cuánto?») se ve como ellas, no como una etiqueta
   pequeña: tres preguntas iguales, tres títulos iguales. */
.campo--pregunta > label { margin-bottom: 8px; font-family: var(--f-titulo); font-weight: 700; font-size: var(--t-l); line-height: 1.12; }
.opcional { font-weight: 400; color: var(--tinta-2); }

/* El error va DOS veces (arriba con enlace, y junto al campo) y nunca solo en
   color: el borde más grueso acompaña a un texto, no lo sustituye. */
.campo input[aria-invalid="true"], .campo select[aria-invalid="true"], .campo textarea[aria-invalid="true"] { border: 2px solid var(--peligro); }
.campo__error { font-size: var(--t-s); font-weight: 600; color: var(--peligro); }
/* El enlace ocupa el aviso ENTERO (5b1): con un mensaje de una línea medía
   17 px de alto, por debajo de los 44 de zona táctil. Ahora la zona es la
   caja del aviso, sin cambiar cómo se ve. */
.aviso--error a { display: block; margin: -12px -14px; padding: 12px 14px; border-radius: 10px; color: inherit; }

/* «Más opciones»: lo que casi nunca se cambia, plegado pero a la vista.
   <details> funciona sin JavaScript. El resumen mide 44 px: 24 de línea + 20.
   ⚠️ UNA SECCIÓN ENTRE DOS LÍNEAS, NO UNA CAJA: la primera versión era una
   caja con su propio relleno dentro de la tarjeta, y a 320 px al desplegable
   de «quién aprueba» le quedaban 163 px: los nombres salían cortados. Se vio
   en la captura en oscuro, no en las medidas de desbordamiento (un <select>
   corta su texto sin desbordar nada). */
.mas { border-top: 1px solid var(--divisor); border-bottom: 1px solid var(--divisor); }
.mas > summary { padding: 10px 0; font-weight: 600; cursor: pointer; }
.mas > summary:hover { color: var(--primario-texto); }
.mas__cuerpo { padding: 4px 0 18px; display: grid; gap: 18px; }

/* Una casilla con su texto: toda la fila es la zona táctil. */
.campo label.casilla { display: flex; align-items: center; gap: 12px; min-height: var(--tactil); cursor: pointer; font-size: var(--t-m); }
/* Deshace lo de «.campo input» (que es para campos de texto) sin subirle la
   especificidad: subirla le ganaría a «.campo-clave input» y el texto de la
   contraseña volvería a meterse debajo del ojo. */
.casilla input { flex: none; width: 22px; min-height: 0; height: 22px; margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent; accent-color: var(--primario); }

/* Mientras se envía: el servidor ya impide el doble alta; esto dice que algo pasa. */
.btn[aria-disabled="true"] { cursor: progress; }

/* ── Datos apilados: la etiqueta encima y el valor debajo ──── */
/* Para valores largos (un correo, «la persona de contacto, con un enlace»):
   a la derecha, a 320 px, se partían en tres líneas pegadas al borde. */
.datos--apiladas { gap: 14px; }
.datos--apiladas > div { display: grid; gap: 2px; justify-content: stretch; }
.datos--apiladas dt { font-size: var(--t-s); }
.datos--apiladas dd { text-align: left; min-width: 0; overflow-wrap: anywhere; }
.linea { display: block; }
.sin-dato { font-weight: 400; color: var(--tinta-2); }

/* ── El recorrido del alta ────────────────────────────────── */
.recorrido { list-style: none; margin: 0; padding: 0; }
.paso { display: flex; align-items: center; gap: 12px; padding: 12px 0; }
/* Desde 5b1 cada paso va dentro de su <li> (y es un enlace si su pantalla
   existe): el borde se pone entre los <li>, no entre los pasos. */
.recorrido > li + li { border-top: 1px solid var(--divisor); }
/* Un paso con pantalla es un enlace de la fila entera: la zona táctil es la
   fila (90 px), no el título. Se sale 8 px a cada lado para que el fondo al
   pasar por encima no quede pegado al texto. */
a.paso { margin-inline: -8px; padding-inline: 8px; border-radius: 10px; color: var(--tinta); text-decoration: none; }
a.paso:hover { background: var(--superficie-2); }
.paso__detalle { font-size: var(--t-s); font-weight: 600; color: var(--tinta); }
.paso__num {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center; font-size: var(--t-s); font-weight: 700;
  background: var(--superficie-2); color: var(--tinta-2);
}
.paso--hecho .paso__num { background: var(--exito-fondo); color: var(--exito); }
.paso--siguiente .paso__num { background: var(--primario); color: var(--sobre-primario); }
.paso__datos { flex: 1 1 0; min-width: 0; display: grid; gap: 2px; }
.paso__titulo { font-weight: 600; }
.paso__explica { font-size: var(--t-s); color: var(--tinta-2); }
.estado--hecho { background: var(--exito-fondo); color: var(--exito); }
.estado--siguiente { background: var(--primario-suave); color: var(--primario-texto); }
.estado--espera { background: var(--superficie-2); color: var(--tinta-2); }

/* ============================================================
   5b1 · Las marcas
   ============================================================ */

/* Una lista DENTRO de una tarjeta: sin su propia sombra, que dentro de otra
   sombra se ve pesada. */
.lista--plana { box-shadow: none; }

/* Un elemento de lista que NO es una fila (texto + botón, como en el reparto).
   Sin esto el <li> no tiene relleno: el texto y el botón quedan pegados al
   borde de la lista y el botón de uno toca el título del siguiente. Mismos
   16 px laterales que .fila. */
.lista__bloque { display: grid; gap: 10px; padding: 16px; }

/* El reparto de una línea: una marca por renglón (ver reparto_para_leer). */
.reparto { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; overflow-wrap: anywhere; }

/* 5e2a · Un momento del calendario: día y hora en la misma fila. minmax(0, …)
   y no 1fr: un 1fr no baja del contenido y el <select> empujaría la hora
   fuera a 320 px. */
.momento { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 7.5rem); gap: 10px; align-items: end; }

/* Un título que no se corta. En la lista de marcas el nombre ES lo que se
   busca: con puntos suspensivos, «Reformas Fernández-Villa…» y «Villaverde
   Interiorismo y Dise…» no se distinguían a 375 px. Pasa a otra línea. */
.fila__titulo--libre { white-space: normal; overflow-wrap: anywhere; }

/* Un título con su chapa al lado (y debajo si no cabe): la chapa como
   columna a la derecha apretaba la explicación hasta cuatro líneas. */
.fila__linea { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0; }

/* Una fila con su gesto al lado («Apuntar su sí»). A 320 px a los datos les
   quedaban 109: la chapa «Esperando al cliente» (131) pisaba el botón y la
   arroba de la cuenta se cortaba. El gesto baja debajo cuando a los datos no
   les llega para la chapa; desde ~346 px de pantalla la fila queda igual. */
.lista--con-gesto > .fila { flex-wrap: wrap; }
.lista--con-gesto > .fila > .fila__datos { flex-basis: 135px; }

/* D · En la lista de clientes, lo que pide el cliente pesa más que quién lo
   lleva: en tinta, no en gris. */
.fila__sub--pide { color: var(--tinta); }

/* 7a2 · En la agenda del Inicio, de QUIÉN es cada hueco pesa más que su
   formato: la agenda mezcla clientes (PLAN §10), y es lo primero que se lee. */
.fila__sub--quien { color: var(--tinta); }

/* 9d · La línea de lo que espera al cliente («Todavía sin abrir →») es un
   ENLACE a su semana: con el color de los enlaces, no en gris, y solo tan
   ancha como su texto —estirada, un toque en el hueco vacío de la fila la
   abriría sin querer—. El padding agranda la zona de toque sin moverla. */
.fila__sub--ir { color: var(--primario-texto); justify-self: start; padding-block: 4px; }

/* «›» en las filas que son una ELECCIÓN (llevan al paso siguiente): en el
   móvil no hay «pasar por encima», y sin ella nada dice que se tocan. */
.fila__ir { flex: none; font-size: var(--t-xl); line-height: 1; color: var(--tinta-2); }

/* Una opción con título y explicación (activa / pausada): la explicación
   dice qué pasa al elegirla, no solo cómo se llama. */
.opcion--doble { align-items: flex-start; padding-block: 12px; }
.opcion--doble input { margin-top: 1px; }
.opcion__textos { display: grid; gap: 2px; min-width: 0; }
.opcion__titulo { font-weight: 600; }
.opcion__explica { font-size: var(--t-s); color: var(--tinta-2); }

/* ============================================================
   5b2 · Cómo habla y sus temas
   ============================================================ */

/* La voz tal como se escribió: con sus saltos de línea, y sin empujar la
   página a lo ancho si alguien pega un enlace largo. */
.voz-texto { white-space: pre-line; overflow-wrap: anywhere; max-width: none; }

/* 6b3c · lo que recibe la IA, TAL CUAL: pre-wrap y no pre-line, porque los
   espacios del principio (las sangrías de las reglas de red) también llegan. */
.texto-ia { white-space: pre-wrap; overflow-wrap: anywhere; max-width: none; font-size: var(--t-s); }

/* Un botón fantasma suelto (no ocupa todo el ancho): a la izquierda, sin
   estirarse en la rejilla de la tarjeta. */
/* ⚠️ `enlace-suelto` es para enlaces SIN caja (btn--fantasma): le quita el
   padding lateral para que no parezca un boton. Puesto sobre uno que SI
   tiene caja (btn--secundario) deja el texto pegado al borde — lo vio
   Joaquim en el enlace a la tanda del Inicio, 02/10. Para esos, btn--corto. */
.enlace-suelto { justify-self: start; padding-inline: 0; color: var(--primario-texto); }
/* La pareja de btn--ancho: en un grid, que el boton NO se estire. */
.btn--corto { justify-self: start; }
/* En gris parecía un texto, no algo que se toca (se vio en la captura).
   Medido con fp2_4a_contraste: 6,32:1 en claro y 10,14:1 en oscuro (y al
   pasar por encima, 8,24:1). El «5,88:1» del comentario del token no es el
   que da la aritmética: se mide, no se copia. */
.enlace-suelto:hover { background: transparent; color: var(--primario-hover); text-decoration: underline; }

/* Un grupo DENTRO de otro (los idiomas «también» dentro de «Idiomas»): su
   leyenda se ve como la etiqueta de un campo, no como otro título. */
.grupo--interno { gap: 6px; }
.grupo--interno > legend.legend-campo { margin-bottom: 6px; font-family: var(--f-ui); font-size: var(--t-s); font-weight: 600; line-height: 1.5; }

/* Al llegar con #voz o #temas (tras guardar), que la barra de arriba no tape
   el título de la sección. Y con #siguiente (C2: validar en el alta), el aviso. */
.lamina[id], .pila[id] { scroll-margin-top: calc(var(--tactil) + 28px); }

/* ============================================================
   5c · Por dónde sale
   ============================================================ */

/* El nombre de una cuenta como título: un usuario de Instagram de 30
   caracteres sin espacios no puede empujar la página a lo ancho. */
.titulo-cuenta { overflow-wrap: anywhere; }

/* ============================================================
   6d1 · Las publicaciones, en dos bolsas
   ============================================================ */

/* Las dos vistas, una al lado de la otra y del mismo ancho. minmax(0, 1fr) y
   no 1fr: en Grid, 1fr no baja del CONTENIDO, y «Pendientes de revisar (12)»
   ensancharía su columna hasta desbordar el móvil. El texto puede partirse en
   dos líneas antes que empujar la página a lo ancho. */
.bolsas { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.bolsas .btn {
  padding-inline: 10px; height: auto; min-height: var(--tactil); padding-block: 8px;
  font-size: var(--t-s); line-height: 1.25; text-align: center; white-space: normal; overflow-wrap: anywhere;
}

/* Un título que está para quien navega con lector de pantalla: la pestaña ya
   dice qué montón se está viendo, pero la sección necesita su nombre. */
.visualmente-oculto {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ── 6e2b · La muestra de la imagen de una marca ──────────────────
   YA NO ES UNA IMITACIÓN: es el PNG de verdad, el mismo que llevarán sus
   posts, servido al vuelo por `clientes/marca/imagen-muestra`.

   Hasta el 6e1b esto era un recuadro de CSS con el color, el logo y el
   nombre. Se parecía mucho, y ese era justo el problema: era una segunda
   fuente de verdad, y el día que cambiara el dibujo de verdad habría
   seguido enseñando lo de antes sin dar ni un error.

   Ningún color llega aquí por variable: el color lo lleva el PNG dentro.
   El borde es por si el color de la marca es casi blanco: sin él la imagen
   se funde con la lámina y no se ve dónde acaba. */
.muestra-imagen {
  display: block; margin-inline: auto; width: min(100%, 256px); height: auto;
  border-radius: var(--radio-m); border: 1px solid var(--divisor);
}

/* El logo de la agencia (10b·1): suele ser HORIZONTAL y viene a su tamaño
   (hasta 1000 px de lado). La CAJA tiene ancho propio y el logo cabe dentro
   (`object-fit: contain`, sin deformarlo) sin pasar de una altura cómoda.
   ⚠️ `min-width: 0`, y es lo que importa: dentro de una `.pila` (grid de
   columna `auto`) la columna crece hasta el MÍNIMO de cada hijo, y el mínimo
   de esta imagen lo saca el navegador de `max-height` × su proporción (un
   logo 3:1 → ~349 px), ponga lo que ponga `width`. Se salía en 320 con
   `width: auto`, con `min(100%, 24rem)` y con `100%` (medido 15/10).
   El borde, por lo mismo que la muestra: un logo blanco no se vería acabar. */
.logo-agencia {
  display: block; margin-inline: auto; width: 100%; min-width: 0; max-width: 24rem; height: auto; max-height: 8rem;
  object-fit: contain; padding: .5rem;
  border-radius: var(--radio-m); border: 1px solid var(--divisor);
}

/* El campo del color: el hex escrito manda, la rueda es la ayuda.
   `minmax(0, …)` y no `auto`: con `auto` un placeholder largo ensancharía la
   columna y la rueda se saldría en 320. */
.campo-color { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .5rem; align-items: center; }

/* `.campo .campo-color__rueda` y no `.campo-color__rueda` a secas: la regla
   de la casa `.campo input` lleva clase + tipo, así que GANA a una clase
   sola. Con una clase se quedaba en 31 px de ancho (medido en vivo) por su
   `padding: 0 12px`, por debajo del objetivo táctil: se veía, se podía
   pulsar mal, y ninguna prueba de HTML lo habría notado. */
.campo .campo-color__rueda {
  inline-size: var(--tactil); block-size: var(--tactil); min-height: var(--tactil);
  padding: 4px; cursor: pointer;
}

/* El campo de fichero. `.campo .campo-fichero` y no la clase sola: la regla de
   la casa `.campo input` lleva clase + tipo y GANA a una clase suelta — la
   misma trampa que se comió la rueda del color. Con el `padding: 0 12px` y la
   altura fija de los campos de texto, el botón «Examinar» que pinta el
   navegador queda cortado por arriba y por abajo. */
.campo .campo-fichero {
  padding: 9px 12px; height: auto; line-height: 1.4; cursor: pointer;
}

/* ── 8b1 · EL CARTEL DE LA CUENTA (la tanda de la semana) ──────────────────
   La sesión semanal son veinte minutos copiando de esta pantalla a la pestaña
   de Meta. El único error que no se puede arreglar desde Meta es publicar en
   la cuenta de OTRO cliente, así que en qué cuenta se está publicando no puede
   salir de la pantalla: por eso es un cartel PEGADO y no un aviso, que se lee
   una vez y se cierra.

   `top`: justo debajo de la barra, que es sticky y mide 61 px (padding 8+8 +
   los 44 de zona táctil + 1 de borde). Se escribe en función de `--tactil`
   para que no se quede vieja el día que la zona táctil cambie. MEDIDO en vivo,
   no calculado a ojo.

   `z-index: 9`: por debajo de la barra (10), que va delante de todo, y por
   encima de las filas, que tienen que pasarle por debajo.

   El par de colores es el MISMO de `.aviso` (fondo `--primario-suave`, texto
   `--primario-texto`): ya está medido y ya está en uso. Un color nuevo aquí
   sería un contraste nuevo que medir. El fondo es sólido a propósito: uno
   translúcido dejaría leer el texto de las filas a través del cartel. */
.cartel-cuenta {
  position: sticky; top: calc(var(--tactil) + 17px); z-index: 9;
  display: grid; gap: 2px;
  padding: 10px 14px; border-radius: var(--radio-m);
  background: var(--primario-suave); color: var(--primario-texto);
  box-shadow: var(--sombra);
}
.cartel-cuenta__etiqueta { font-family: var(--f-ui); font-size: var(--t-xs); font-weight: 600; letter-spacing: .07em; text-transform: uppercase; }
/* `overflow-wrap: anywhere` y sin `nowrap`: un usuario de Instagram de 30
   caracteres más « · Instagram» no cabe a 320 px, y aquí no se puede recortar
   con puntos suspensivos — un nombre de cuenta a medias es justo lo que hace
   publicar en la cuenta equivocada. Que ocupe dos líneas. */
.cartel-cuenta__cuenta { font-size: var(--t-m); overflow-wrap: anywhere; }
.cartel-cuenta__cliente { font-size: var(--t-s); overflow-wrap: anywhere; }

/* 8b2a · EL POST LISTO PARA COPIAR, dentro de la fila de su pieza.

   Rejilla propia y no la de la fila: `.fila__datos` junta el título y sus
   subtítulos SIN separación a propósito (son un bloque), y un campo de texto
   pegado al subtítulo se lee como parte de él. El margen va ARRIBA: así el
   botón de una pieza no se pega al título de la siguiente. */
.copiar-post { display: grid; gap: 8px; margin-top: 8px; }

/* El campo no está dentro de un `.campo`, así que no hereda nada: todo
   explícito. Fondo `--superficie-2` (el de `.campo-copia`) para que se vea que
   es algo que se copia y no algo que se escribe, y la tipografía de la interfaz
   y NO monoespaciada: esto es prosa en español o catalán, y en monoespaciada se
   lee peor y ocupa más ancho justo a 320 px. `resize: vertical` para quien
   quiera ver un post largo entero sin desplazarse dentro del campo. */
/* `field-sizing: content`: donde el navegador lo entiende, el campo mide lo que
   ocupa su texto de verdad y no hay que adivinar cuántos renglones se parten.
   Donde no (Safari, y es el de Carolina en el iPhone), manda el `rows` que
   calcula la pantalla, que va tirando por lo bajo a propósito. Los dos caminos
   acaban igual: que los hashtags se vean sin desplazarse dentro del campo. */
.campo-post {
  width: 100%; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--borde-campo); background: var(--superficie-2); color: var(--tinta);
  font: 400 var(--t-s)/1.5 var(--f-ui); resize: vertical; field-sizing: content;
  /* El tope, para los DOS caminos: sin él, `field-sizing` haría que un post
     largo creciera sin freno y empujara el cartel de la cuenta fuera de la
     pantalla. 24rem es más o menos lo que dan los 14 renglones del `rows`, así
     que el campo se ve igual de alto se entienda o no `field-sizing`. */
  max-block-size: 24rem;
}

/* 8b2b · Bajar la imagen de una pieza de la tanda.

   La miniatura y el botón, en la misma línea: la miniatura existe para poder
   comprobar de un vistazo que lo que se baja es la imagen de ESTE post, así
   que tiene que verse justo al lado del gesto que la baja, no arriba del todo.

   `minmax(0, 1fr)` en la columna del botón y no `1fr`: con `1fr` el texto del
   botón no puede bajar de su contenido, y a 320 px eso ensancharía la fila y
   sacaría la miniatura. */
.bajar-imagen {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 10px; align-items: center; margin-top: 8px;
}

/* 4:5 (1080x1350), la proporción con la que se dibuja y la que Meta acepta sin
   recortar. El alto se deja calcular al navegador a partir del `width`/`height`
   del HTML: así la fila no salta cuando la imagen acaba de cargar. */
.bajar-imagen__muestra {
  inline-size: 64px; block-size: auto; display: block;
  border-radius: var(--radio-m); border: 1px solid var(--divisor);
  background: var(--superficie-2);
}

/* 8b2d · el gesto de la tanda: «ya está en Meta», con su hora. Va DENTRO de su
   pieza y separado por una línea, no al final de la lista: lo que se marca es
   ESTA fila, y un botón lejos de lo que afecta es el que acaba marcando la de
   al lado — el mismo error que el cartel de la cuenta existe para evitar.
   El campo no lleva ancho propio: está en un `.campo`, que ya lo pone al 100 %
   y le da el alto táctil. Dos sitios diciendo el ancho del mismo campo es uno
   de los dos quedándose viejo. */
.marcar {
  display: grid; gap: 8px; margin-top: 10px;
  padding-top: 10px; border-top: 1px solid var(--divisor);
}

/* ============================================================
   9b1 · La pantalla pública del enlace del cliente
   ============================================================
   La ve el CLIENTE en su móvil, sin cuenta, sin menú y sin más página que
   esta: su semana, pieza a pieza, tal cual va a salir. Se maqueta a 320 px
   primero; el ancho tope es el de leer un post cómodo, no el del panel. */
.publico { width: 100%; max-width: 560px; margin: 0 auto; padding: 24px 16px 48px; display: grid; gap: 16px; }
.publico h1 { margin: 0; font-size: var(--t-xl); }
.publico__cabecera { display: grid; gap: 4px; }
.publico__cabecera .secundario { margin: 0; }
.publico__intro { margin: 0; }
.publico__caja { display: grid; gap: 10px; }
.publico__caja h2 { margin: 0; font-size: var(--t-l); }
.publico__caja .secundario { margin: 0; }
.publico__pie { margin: 0; }

.publico__lista { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }

/* Una pieza = una tarjeta que se lee como el post que va a ser: cuándo y por
   dónde arriba, la imagen entera, y debajo su texto con sus saltos de línea. */
.pieza {
  background: var(--superficie); border: 1px solid var(--divisor);
  border-radius: var(--radio-m); box-shadow: var(--sombra);
  overflow: hidden; display: grid;
}
.pieza__cabecera { display: grid; gap: 2px; padding: 14px 16px 10px; }
.pieza__cuando { margin: 0; font-weight: 600; }
/* `anywhere` y no ellipsis: en el móvil del cliente, un usuario largo de
   Instagram tiene que poder LEERSE entero — aquí no hay otra pantalla donde
   mirarlo, así que baja de línea en vez de cortarse con puntos. */
.pieza__donde { margin: 0; font-size: var(--t-s); color: var(--tinta-2); overflow-wrap: anywhere; }
/* 9e2 · ✋ La pieza que su silencio NO cubre. En la cabecera y no junto a los
   botones: la línea de arriba dice «menos las marcadas con ✋», y se buscan
   bajando con el dedo, antes de la imagen. */
.pieza__mano { margin: 4px 0 0; font-weight: 600; }
/* 4:5 (1080×1350), la proporción con la que se congela (8b2b). El alto lo
   calcula el navegador del width/height del HTML: la lista no salta al cargar. */
.pieza__imagen {
  display: block; inline-size: 100%; block-size: auto;
  background: var(--superficie-2);
  border-block: 1px solid var(--divisor);
}
.pieza__texto { margin: 0; padding: 12px 16px 0; white-space: pre-wrap; overflow-wrap: break-word; }
.pieza__hashtags { margin: 0; padding: 6px 16px 0; font-size: var(--t-s); color: var(--tinta-2); overflow-wrap: anywhere; }
/* Lo último de la tarjeta cierra con su aire, sea el texto, los hashtags o
   (en una pieza sin imagen todavía) la propia cabecera. */
.pieza > :last-child { padding-bottom: 14px; }
.pieza > .pieza__imagen:last-child { padding-bottom: 0; }

/* 9b2 · Los gestos del cliente, la pregunta del silencio y el registro.
   Mismo criterio que arriba: 320 px primero, el dedo manda (botones a todo
   el ancho en el móvil; en pantallas anchas se reparten). */
.publico__aviso { margin: 0; }
.publico__todas { margin: 0; display: grid; }

.publico__silencio { display: grid; gap: 10px; padding: 14px 16px; }
.publico__silencio h2 { margin: 0; font-size: var(--t-l); }
.publico__silencio p { margin: 0; }
/* 9e2 · f · Las dos respuestas, SIEMPRE una encima de la otra, también en
   escritorio: en dos columnas iguales «Prefiero aprobarlo siempre yo» no
   cabía y dejaba «yo» solo en la segunda línea. La página no pasa de 560 px:
   apilados caben los dos en una línea, diga lo que diga el texto. */
.publico__silencio-botones { display: grid; gap: 8px; }
/* La red: a 320 px la frase larga cabe por 0,3 px. Si un móvil la pinta un
   pelo más ancha, que parta «Prefiero aprobarlo / siempre yo» y no deje «yo»
   solo. Mientras quepa en una línea no hace nada, y el navegador que no la
   conozca se queda como estaba. */
.publico__silencio-botones .btn { text-wrap: balance; }

.pieza__acciones { display: grid; gap: 8px; padding: 12px 16px 0; }
.pieza__acciones form { margin: 0; display: grid; }
/* El summary ES el botón secundario de abrir el comentario: nativo, sin JS.
   `list-style: none` + ::-webkit-details-marker fuera = sin la flechita. */
.pieza__cambio summary {
  list-style: none; cursor: pointer; text-align: center;
  padding: 10px 14px; border: 1px solid var(--divisor); border-radius: var(--radio-m);
  font-weight: 600; background: var(--superficie-2);
}
.pieza__cambio summary::-webkit-details-marker { display: none; }
.pieza__cambio[open] summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.pieza__cambio-form {
  display: grid; gap: 8px; padding: 12px;
  border: 1px solid var(--divisor); border-top: 0;
  border-radius: 0 0 var(--radio-m) var(--radio-m);
}
.pieza__cambio-form .campo { margin: 0; }
@media (min-width: 480px) {
  /* Lado a lado solo cuando caben de verdad; el detalle abierto ocupa toda
     la fila para que el texto tenga sitio. */
  .pieza__acciones { grid-template-columns: 1fr 1fr; }
  .pieza__cambio { grid-column: auto; }
  .pieza__cambio[open] { grid-column: 1 / -1; }
}

/* Lo ya decidido: tarjeta en reposo — misma letra, menos volumen. El registro
   es la confirmación del gesto, así que se lee como una afirmación, no como
   un adorno. */
.pieza--decidida { background: var(--superficie-2); box-shadow: none; }
.pieza__registro { margin: 0; padding: 10px 16px 0; font-weight: 600; }
.pieza__registro-comentario {
  margin: 0; padding: 4px 16px 0; font-size: var(--t-s); color: var(--tinta-2);
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* ============================================================
   10b·3 · El informe del mes (la página que se guarda como PDF)
   ============================================================ */
/* Más ancho que las fichas: es un documento, y en escritorio se lee como
   tal. En el móvil manda el mismo 16 px de margen que todo lo demás. */
.pagina--informe { max-width: 760px; }
/* La barra de la página (volver, Guardar como PDF, la ayuda): NO sale en el
   papel, ver @media print. */
.informe__barra { display: grid; gap: 10px; }

.informe { display: grid; gap: 28px; }
.informe__portada { display: grid; gap: 10px; padding: 24px 0 16px; border-bottom: 1px solid var(--divisor); }
/* El logo de la agencia, a lo ancho que quepa: el alto lo calcula el navegador
   del width/height del HTML, y `min-width: 0` para que un logo apaisado no
   ensanche la portada a 320. */
.informe__logo { display: block; max-width: 220px; width: auto; height: auto; max-height: 96px; min-width: 0; }
.informe__agencia { font-family: var(--f-titulo); font-weight: 700; font-size: var(--t-l); }
.informe__mes { font-size: var(--t-l); font-weight: 600; }
.informe__pie { color: var(--tinta-2); }

.informe__seccion { display: grid; gap: 12px; }
.informe__vistazo { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
/* `anywhere`: «Instagram · @floristeriasol · Carrusel — 10 de 12 · faltan 2»
   no cabe en una línea a 320, y tiene que leerse entero, no cortarse. */
.informe__vistazo li { font-weight: 600; overflow-wrap: anywhere; }

/* Una pieza del informe: la miniatura a la izquierda y los datos a la
   derecha, también en el móvil (a 320 quedan 96 + 12 + ~180 px de texto).
   `minmax(0, 1fr)` y no `1fr`: con `1fr` un enlace largo ensancharía la
   columna y la tarjeta se saldría de la página. */
.informe__piezas { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.informe__pieza { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 12px; padding: 12px; align-items: start; }
.informe__miniatura, .informe__sin-imagen {
  display: block; width: 96px; height: 120px; object-fit: cover;
  border-radius: 8px; background: var(--superficie-2); border: 1px solid var(--divisor);
}
.informe__pieza-datos { display: grid; gap: 4px; min-width: 0; }
.informe__pieza-datos p { max-width: none; }
.informe__enlace { font-weight: 600; overflow-wrap: anywhere; }
.informe__aprobacion { font-size: var(--t-s); color: var(--tinta-2); }

.informe__incidencias { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.informe__incidencias > li { display: grid; gap: 4px; }
.informe__incidencia-piezas { margin: 0; padding-left: 20px; display: grid; gap: 4px; }

@media (min-width: 640px) {
  .informe__pieza { grid-template-columns: 120px minmax(0, 1fr); }
  .informe__miniatura, .informe__sin-imagen { width: 120px; height: 150px; }
}

/* ============================================================
   10c · La zona «Informes»: cada cliente, sus doce meses
   ============================================================ */
/* El año en el centro y los vecinos a los lados, cada uno en SU columna: si
   falta uno (no hay nada antes, o es el año de hoy), el año no se mueve. */
.anios { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; }
.anios__antes { grid-column: 1; justify-self: start; }
.anios__actual { grid-column: 2; }
.anios__despues { grid-column: 3; justify-self: end; }

/* Sin tarjeta, a propósito: el borde y el relleno de una `.lista` le quitan
   a las celdas los píxeles que necesitan para ser tocables a 320. */
.informes-zona { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }
.informes-zona > li { display: grid; gap: 8px; min-width: 0; }
.informes-zona > li + li { padding-top: 16px; border-top: 1px solid var(--divisor); }
.informes-zona__nombre { font-size: var(--t-m); font-weight: 600; overflow-wrap: anywhere; }

/* Doce meses. En el móvil, dos filas de seis (enero-junio, julio-diciembre):
   a 320 quedan 288 px, y seis de 44,6 con 4 de hueco es el mínimo táctil.
   Desde 640, una sola fila. `minmax(0, 1fr)` y no `1fr`: con `1fr` la
   columna no baja de su contenido y la fila se saldría de la página. */
.meses { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; }
.mes {
  min-height: var(--tactil); display: grid; place-content: center; justify-items: center; gap: 3px;
  border: 1px solid transparent; border-radius: 8px;
  color: var(--tinta-2); font-size: var(--t-xs); font-weight: 600; line-height: 1; text-decoration: none;
}
.mes__simbolo { font-size: var(--t-s); font-weight: 700; }
/* Los colores, los de los estados de siempre (ratios medidos el 20/10, el
   más justo 4,84:1 el aviso en claro). Al pasar por encima NO cambia el
   fondo —el ratio es el de reposo—: se marca el borde. */
.mes--generado { background: var(--exito-fondo); color: var(--exito); }
.mes--falta { background: var(--aviso-fondo); color: var(--aviso); border-color: currentColor; }
.mes--sin-contrato { background: var(--superficie-2); }
.mes--por-llegar { border-color: var(--divisor); }
a.mes:hover { box-shadow: inset 0 0 0 1px currentColor; border-color: currentColor; }
/* La leyenda se parte entre una pareja y la siguiente, nunca dentro. */
.leyenda > span { white-space: nowrap; }

@media (min-width: 640px) {
  .meses { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 6px; }
}

/* ── Al imprimir: solo el informe ──────────────────────────────
   El PDF lo hace el navegador (Hostinger no tiene exec). Fuera la barra de
   la app (arriba y la navegación de abajo) y la barra de la página; la
   portada ocupa su página; una pieza no se parte en dos hojas; un título no
   se queda solo al pie. Sin un solo color suelto: los tokens de siempre. */
@media print {
  @page { size: A4; margin: 16mm; }
  .barra, .barra__nav, .informe__barra { display: none; }
  .barra ~ .pagina { padding: 0; }
  .pagina--informe { max-width: none; margin: 0; padding: 0; gap: 0; }
  body { background: var(--superficie); }
  /* Chrome NO parte bien un `grid` entre hojas: lo que salta a la hoja
     siguiente se pinta ENCIMA de lo anterior (visto en SU recorrido, 20/10:
     «Lo que no salió» sobre la última tarjeta). En papel, todo lo que puede
     partirse es un BLOQUE con margen; la tarjeta, que no se parte, sigue
     siendo grid. */
  .informe, .informe__seccion, .informe__vistazo, .informe__piezas, .informe__incidencias, .informe__incidencias > li { display: block; }
  .informe__seccion { margin-top: 22px; }
  .informe__seccion > h2 { margin: 0 0 12px; }
  .informe__vistazo > li + li { margin-top: 8px; }
  .informe__piezas > li + li, .informe__incidencias > li + li { margin-top: 14px; }
  .informe__incidencia-piezas { margin-top: 4px; }
  .informe__portada { min-height: 55vh; align-content: center; break-after: page; border-bottom: 0; }
  .informe__seccion h2 { break-after: avoid; }
  .informe__pieza, .informe__incidencias > li, .informe__vistazo li { break-inside: avoid; }
  .pieza, .lamina { box-shadow: none; }
}
