/*
 * PWA del carnet — hoja de estilo. Consume los tokens compartidos de
 * /shared/css/tokens.css; aquí no se define ni un color suelto.
 * Mobile-first: la pantalla del carnet se enseña a un comerciante con el
 * móvil en la mano, así que el QR manda y todo lo demás cede espacio.
 */
/* La base —el reset, la tipografía y el fondo— vive en
   /shared/css/portal.css, que cargan las tres páginas. Aquí solo lo que es
   propio del carnet. */

/*
 * El recorte de la pantalla —el relleno de `env(safe-area-inset-*)` en el
 * cuerpo— vive en shared/css/tokens.css, que lo cargan TODAS las páginas.
 * Estuvo aquí, o sea solo en la shell, y la zona de gestión se dibujaba por
 * debajo del reloj.
 */

.vista { display: none; }
.vista--activa { display: block; }

/* ── Aviso de conectividad ───────────────────────────────────────────── */
/*
 * ── LES COBERTES: L'ARRENCADA I LA FALTA DE XARXA ───────────────────────
 *
 * Substitueixen `.avis`, la tira vermella del peu que deia «Cal connexió per
 * mostrar el carnet». Idea de David: una capa al mig amb la marca, que a
 * l'arrencada dona la benvinguda i sense xarxa explica què s'espera.
 *
 * z-index 40: per damunt de tot el que hi ha (contingut 10 · full 19 · barra
 * 20 · modal 30). És l'única cosa del projecte que ha de tapar un modal — si
 * no hi ha xarxa, tampoc funciona el que hi hagi obert a sobre.
 */
.coberta {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--afa-espai-5);
  padding: var(--afa-espai-6);
}

.coberta__marca {
  width: 15rem;
  max-width: 70%;
  height: auto;
  display: block;
}

/*
 * L'SPINNER DE L'ARRENCADA — i el retard és tota la decisió.
 *
 * Dues animacions sobre el mateix element: una que gira per sempre i una que
 * el fa aparèixer als 400 ms amb `both`, o sigui que abans d'això està a
 * opacitat 0. Sense JavaScript, perquè una coberta que depèn d'un script és
 * una app que es queda en blanc el dia que el script falli — que és la mateixa
 * raó que ja està escrita a la shell per a la coberta sencera.
 *
 * Amb moviment reduït la regla global de `tokens.css` apaga les dues: queda
 * un anell quiet i visible de seguida, que és el que toca.
 */
.coberta__spin {
  width: 2.125rem;
  height: 2.125rem;
  border-radius: 50%;
  border: 3px solid var(--afa-calid-100);
  border-top-color: var(--afa-accent);
  animation: coberta-gira .85s linear infinite,
             coberta-apareix .3s ease .4s both;
}

@keyframes coberta-gira   { to { transform: rotate(360deg); } }
@keyframes coberta-apareix { from { opacity: 0; } to { opacity: 1; } }

.coberta__text {
  margin: 0;
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-fort);
  color: var(--afa-text-suau);
  text-align: center;
}

/*
 * L'ARRENCADA. Opaca i NOMÉS dins de la PWA: en una pestanya del navegador,
 * una benvinguda a pantalla completa cada vegada que es carrega la pàgina
 * seria una nosa. `display-mode: standalone` és la mateixa senyal que llegeix
 * `AFA.instalada()`, però aquí en CSS, que és el que permet que marxi sense
 * que cap script hi participi.
 *
 * El fons és EXACTAMENT el `background_color` del manifest: el sistema pinta
 * la seva pantalla d'arrencada amb aquest color i la icona a sobre, i si els
 * dos no coincidissin es veuria el salt d'una a l'altra.
 */
.coberta--arrenca {
  display: none;
  background: #FBF8F3;
}

/*
 * ── QUANT DURA, I PER QUÈ AQUEST NÚMERO ─────────────────────────────────
 *
 * 1,5 s: 0,9 quieta i 0,6 de fosa. Va començar a 0,7 i David va dir que «ni
 * se ve», i tenia raó per un motiu que no es veu des d'aquí: **a l'iPhone no
 * som la primera pantalla**. El sistema en pinta una de seva mentre carrega
 * la WebView —la icona damunt del `background_color`— i la nostra animació
 * arrenca quan la pàgina es pinta, que pot ser mentre aquella encara tapa.
 * O sigui que dels 0,7 se'n veien els últims.
 *
 * EL QUE COSTA, dit clar: és temps abans del carnet. Ara bé, el carnet no
 * està llest abans —el token es demana mentre això es veu— i la coberta
 * només surt en un arrencada EN FRED: si iOS només tenia l'app suspesa,
 * restaura la pàgina sense recarregar i aquí no passa res. Al mostrador, que
 * és on el temps costa de veritat, l'app sol estar viva.
 *
 * És un sol número. Si es fa llarg, es baixa aquí i enlloc més.
 */
@media (display-mode: standalone) {
  .coberta--arrenca {
    display: flex;
    animation: afa-arrenca 1.5s ease-in forwards;
  }
}

/*
 * `visibility` a més d'`opacity`, i `forwards` perquè l'últim fotograma es
 * quedi: amb `opacity: 0` tot sol, la capa seguiria per damunt de la pantalla
 * interceptant els tocs. I amb `prefers-reduced-motion` la durada baixa a
 * 0,01 ms per la regla global de `tokens.css`, o sigui que l'animació acaba
 * igualment i la capa desapareix — que és el comportament correcte, no un
 * efecte secundari.
 */
@keyframes afa-arrenca {
  0%, 60% { opacity: 1; visibility: visible; }
  100%    { opacity: 0; visibility: hidden; }
}

/*
 * LA FALTA DE XARXA. Translúcida a posta: es veu que l'app segueix sent
 * l'app i que això és un estat, no una pantalla d'error. I no marxa sola —
 * la treu `ambConnexio()` quan una petició de veritat torna a funcionar.
 */
.coberta--xarxa {
  /*
   * El velo vive en `tokens.css` y no escrito aquí, y en `rgba` y no con
   * `color-mix()`: es la regla que ya está anotada allí — `color-mix` pide
   * navegadores recientes y, si no se entiende, la declaración se cae ENTERA
   * y la capa se queda transparente. Aquí eso sería el carnet visible detrás
   * de un texto que dice que no hay conexión.
   */
  background: var(--afa-vel-clar);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

/* ── Entrada ─────────────────────────────────────────────────────────── */
.login {
  max-width: 24rem;
  margin: 0 auto;
  padding: var(--afa-espai-7) var(--afa-espai-5);
  text-align: center;
}

/*
 * ── LA MARCA DE L'ENTRADA ────────────────────────────────────────────────
 *
 * EL BANNER, NO LA ICONA. Aquí hi havia la icona quadrada de l'app amb el nom
 * escrit a sota, i eren dues coses que deien el mateix: el banner ja porta
 * «AFA EL CIM» i l'eslògan dins del dibuix. Decisió de David.
 *
 * I abans d'això hi va haver una icona que es veia com una taca, que és el que
 * va portar fins aquí: el crema de la targeta (#EAE3D7) contra el fons de
 * l'app (#FBF6EE) dóna **1,19:1** —o sigui res— així que l'única cosa que la
 * dibuixava era la `box-shadow` que li posàvem al CSS, i a sobre amb un
 * `border-radius` propi damunt d'un PNG que ja porta les seves cantonades. El
 * contorn que es veia no era el de la icona: era el del rectangle del CSS.
 *
 * Amb el banner el problema desapareix sol: no té fons. Val la pena deixar-ho
 * escrit perquè la temptació de tornar-hi a posar una caixa vindrà de l'aspecte
 * «buit» que fa una marca sense contorn, i aquí el buit és la solució.
 *
 * L'AMPLADA MANA I L'ALÇADA SURT DE LA PROPORCIÓ (`height: auto`): el fitxer
 * és 768x176 i el dia que canviï de mides no s'ha de deformar. 15rem és més
 * gran que els 14,25 de la capçalera —aquí és el protagonista, allà és una
 * xapa— i amb `max-width: 100%` encongeix en un mòbil de 320 en comptes de
 * desbordar.
 */
.login__marca {
  margin: 0 0 var(--afa-espai-5);
}

.login__banner {
  /*
   * 22,5rem = els 15 d'abans + un 50%, que és el que va demanar David: «se ve
   * muy pequeño para una landing». Aquí la marca no és una xapa de capçalera,
   * és el reclam de la pàgina.
   *
   * ON TOPA, perquè la xifra no s'aconsegueix sencera a tot arreu i val més
   * saber-ho: `max-width: 100%` la reté a l'amplada de la columna. En un mòbil
   * de 375 la columna en dóna 327 (375 menys el coixí de `.login`) i en
   * escriptori 352 (la primera columna de la graella és `minmax(0, 22rem)`).
   * O sigui que creix un 47% a l'escriptori i un 36% al mòbil, i el que la
   * frena no és aquest número sinó el coixí. Es podria guanyar la resta
   * traient-li el coixí al logotip amb marges negatius, i llavors la marca
   * tocaria els caires de la pantalla: no és millor, és una altra cosa.
   */
  width: 22.5rem;
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
}

/*
 * ── LA TRIA DE L'ENTRADA ────────────────────────────────────────────────
 *
 * Dos botons i una frase. No porta caixa ni vora: el que hi ha a la pantalla
 * és el logotip i una decisió, i qualsevol contorn hi afegeix una peça que no
 * separa res del que té a sobre —el fons ja és el de la pàgina.
 *
 * El buit de sota és el que hi havia entre el títol i el formulari, així que
 * la pàgina no salta quan es passa d'una cosa a l'altra.
 */
.tria {
  display: flex;
  flex-direction: column;
  gap: var(--afa-espai-3);
  margin: 0 0 var(--afa-espai-6);
}

.tria__ajuda {
  margin: 0 0 var(--afa-espai-2);
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  line-height: 1.5;
}

.login__titol {
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-normal);
  color: var(--afa-text-suau);
  margin: 0 0 var(--afa-espai-6);
}

.login__oblidada {
  margin: var(--afa-espai-4) 0 0;
  text-align: center;
  font-size: var(--afa-mida-s);
}
/* Eran --afa-muted y --afa-esp-m, que NO existen en tokens.css. Una variable
   inexistente no da error: invalida la declaración al calcular el valor y la
   propiedad se hereda, así que el enlace salía del color del texto y el
   margen se quedaba en cero. Un fallo que no se ve hasta que se compara. */
.login__oblidada a { color: var(--afa-text-suau); }

.login__ajuda {
  color: var(--afa-text-suau);
  font-size: var(--afa-mida-s);
  margin: 0 0 var(--afa-espai-4);
  text-align: center;
}

.login__form { text-align: left; }

.camp { display: block; margin-bottom: var(--afa-espai-4); }

.camp__etiqueta {
  display: block;
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--afa-text-suau);
  margin-bottom: var(--afa-espai-2);
}

.camp__input {
  width: 100%;
  min-height: var(--afa-tap-min);
  padding: var(--afa-espai-3);
  font-family: inherit;
  font-size: var(--afa-mida-m);
  color: var(--afa-text);
  background: var(--afa-blanc);
  border: 2px solid var(--afa-vora);
  border-radius: var(--afa-radi-s);
}

.camp__input:focus-visible {
  outline: 3px solid var(--afa-accent);
  outline-offset: 1px;
  border-color: var(--afa-primari);
}

.boto {
  font-family: inherit;
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-fort);
  min-height: var(--afa-tap-min);
  padding: var(--afa-espai-3) var(--afa-espai-5);
  border: 0;
  border-radius: var(--afa-radi-s);
  cursor: pointer;
}

.boto:focus-visible { outline: 3px solid var(--afa-accent); outline-offset: 2px; }
.boto[disabled] { opacity: .6; cursor: default; }

/*
 * ── QUÈ VOL DIR `--primari`, QUE NO ÉS «el botó important» ───────────────
 *
 * És **l'acció d'un FORMULARI**: per això ocupa tot l'ample i porta marge a
 * dalt. Allà és correcte —hi ha un sol camí endavant i el polze l'ha de trobar
 * sense apuntar— i és el que fan «Entrar», «Crea el compte» o «Entra a la
 * família».
 *
 * NO ÉS per a una acció solta enmig d'una pantalla. Posar-l'hi la converteix
 * en una barra de caire a caire, que és el que va passar amb «Afegir membre» a
 * «La meva família» i el que David va haver d'assenyalar dues vegades el
 * mateix dia — la primera va ser la caixa del QR.
 *
 * QUÈ FER LLAVORS: mirar on va l'acció abans de buscar-li una classe. Aquella
 * va acabar sent la icona de la cantonada de la capçalera (`.pagina__accio`,
 * a portal.css), i amb això va desaparèixer el problema i també el
 * `.boto--accio` que s'havia escrit per resoldre'l — va viure un dia i no el
 * fa servir ningú, així que se'n va. Una classe que no pinta res és un
 * comentari que menteix esperant torn.
 */
.boto--primari {
  display: block;
  width: 100%;
  background: var(--afa-primari);
  color: var(--afa-primari-text);
  margin-top: var(--afa-espai-5);
}

.boto--text {
  background: none;
  color: var(--afa-primari);
  text-decoration: underline;
  padding: var(--afa-espai-2);
}

/* ── Notas y avisos ──────────────────────────────────────────────────────
   Sin franja lateral: marca circular con el mismo lenguaje de símbolos que el
   validador (✓ / ✗ / !) y fondo teñido. El símbolo va en un pseudoelemento
   para no tener que tocar el HTML ni el JavaScript que escribe estos textos. */
/*
 * OJO: `.nota` es un flex y su marca circular es el `::before`, así que TODO
 * el contenido tiene que ir en UN SOLO hijo. Con varios (un `<strong>`, un
 * `<br>` y un texto, por ejemplo) cada uno se convierte en un elemento flex
 * hermano y el mensaje sale en columnas — y el `<br>` no salva nada, porque
 * dentro de un flex no hay línea que romper.
 */
.nota {
  display: flex;
  align-items: flex-start;
  gap: var(--afa-espai-3);
  padding: var(--afa-espai-3) var(--afa-espai-4);
  border-radius: var(--afa-radi-m);
  font-size: var(--afa-mida-s);
  line-height: 1.5;
  text-align: left;
}

.nota::before {
  content: '!';
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-molt);
  line-height: 1;
}

.nota--error {
  background: var(--afa-vermell-050);
  color: var(--afa-vermell-600);
  font-weight: var(--afa-pes-fort);
}
.nota--error::before {
  content: '✕';
  background: var(--afa-vermell-600);
  color: var(--afa-blanc);
}

/*
 * `.nota--ok` se retiró en la limpieza del 7 de septiembre por estar sin usar,
 * y volvió al día siguiente con la pantalla de contraseña nueva. No fue un
 * error retirarla —entonces no la usaba nadie— pero deja la lección: en un
 * proyecto vivo, "código muerto" a veces solo significa "todavía no".
 */
.nota--ok { background: var(--afa-verd-050); color: var(--afa-text); }
.nota--ok::before {
  content: '\2713';
  background: var(--afa-verd-600);
  color: var(--afa-blanc);
}

.nota--avis { background: var(--afa-taronja-050); color: var(--afa-text); }
.nota--avis::before {
  background: var(--afa-taronja-500);
  color: var(--afa-blau-900);
}


.error {
  background: var(--afa-vermell-050);
  color: var(--afa-vermell-600);
  padding: var(--afa-espai-3);
  border-radius: var(--afa-radi-m);
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-fort);
  margin: var(--afa-espai-4) 0 0;
}

/* ── Cabecera de la app ──────────────────────────────────────────────────
 *
 * `.capcalera` YA NO SE DEFINE AQUÍ: vive en /shared/css/portal.css y en
 * ningún otro sitio. Estaba escrita dos veces —aquí y en registre.css—, con
 * reglas parecidas y no iguales, que es exactamente la trampa que este
 * proyecto tiene nombrada: duplicar presentación cuesta trabajo, duplicarla
 * mal hace que el proyecto parezca dos proyectos. Hay prueba en
 * bin/proves/carnet.php de que solo hay una definición.
 */

/* ── Carnet ──────────────────────────────────────────────────────────── */
/*
 * `text-align: left` i no `center`. La targeta anterior anava centrada i el
 * `text-align` es va quedar aquí quan va arribar la credencial del disseny,
 * que és alineada a l'esquerra; es corregia 1.900 línies més avall, en un
 * segon bloc amb el mateix nom. Ara és una sola declaració.
 */
.carnet {
  max-width: 26rem;
  margin: 0 auto;
  padding: var(--afa-espai-4);
  text-align: left;
}

/* ── La credencial ───────────────────────────────────────────────────────
 *
 * La tarjeta que ve la familia. Fondo claro y opaco por obligación técnica,
 * no estética: encima va un QR que tiene que leerse con la cámara de otro
 * móvil, así que ni degradados ni transparencias por debajo.
 *
 * overflow: hidden es lo que recorta los tres ángulos de color contra el
 * redondeo de las esquinas. Sin eso asoman por fuera de la tarjeta.
 */
.credencial {
  position: relative;
  overflow: hidden;
  background: var(--afa-marina);
  color: var(--afa-blanc);
  border: 0;
  border-radius: 1.5rem;   /* 24px, el del disseny */
  box-shadow: var(--afa-ombra-2);
  padding: var(--afa-espai-4);
  /*
   * L'angle taronja és l'únic que queda dels tres: els dos de baix eren blaus
   * sobre blanc i aquí serien invisibles. El relleno inferior de 2,75rem que
   * reservava el seu forat va marxar amb ells, i això és el que deia el segon
   * bloc que hi havia més avall amb aquest mateix nom.
   */
  --angle-sup: 4.625rem;                 /* los 74px del diseño */
  --angle-sup-color: var(--afa-taronja-viu);
  --angle-dre-color: transparent;
  --angle-esq-color: transparent;
}

/*
 * Ángulos de color. Son el motivo de la casa: la misma diagonal del
 * triángulo del logotipo, repetida en las esquinas.
 *
 * El de abajo a la izquierda es azul medio, no rojo como en la referencia
 * impresa: en esta pantalla el rojo quiere decir CADUCAT y no puede aparecer
 * de adorno junto a un carnet vigente.
 *
 * Van detrás del contenido (z-index 0 contra 1) y ninguna fila de datos cae
 * encima de ellos: de eso se encarga el relleno inferior de la tarjeta.
 */
/*
 * Las medidas y los colores de la tarjeta son los VALORES POR DEFECTO del
 * componente `.angle` de portal.css, así que aquí no hay que decir nada: la
 * credencial es el sitio donde nacieron y quien los cambie los cambia para
 * ella. El portal declara los suyos con las mismas variables.
 */

/*
 * ── AQUÍ HI HAVIA EL LOGOTIP I EL TÍTOL DE LA TARGETA ───────────────────
 *
 * `.credencial .marca` —el lockup dins de la targeta, amb el filet taronja— i
 * `.credencial__titol`, el «Carnet de família sòcia». El disseny 2A se'ls va
 * endur ja fa dies: el logotip puja a la capçalera i l'antetítol («CARNET DE
 * SOCI · 2026-2027») diu el que deia el títol. També se'n va la parella de
 * `bin/contrast.php` que mesurava el taronja del títol sobre blanc, que era
 * l'única pareja del projecte que demanava «text gran» — i ja no hi ha cap
 * text al qual exigir-li-ho.
 *
 * El `z-index: 1` que els aixecava per damunt dels angles es queda per a la
 * caixa del QR, que sí que hi és.
 */
.credencial .carnet__marc { position: relative; z-index: 1; }

/*
 * LA CINTA DEL CURSO se esconde cuando el carnet está caducado: el curso se
 * deduce de la fecha de vigencia, y esa fecha tampoco se muestra. Anunciar
 * "Curs 2026-2027" al lado de un CADUCAT es contradecirse.
 *
 * Su ASPECTO es `.cinta`, definido en portal.css y compartido con el resumen
 * de escritorio: eran las mismas ocho declaraciones y el resumen enseñaba el
 * curso como texto plano, o sea el mismo dato dicho de dos maneras. Aquí no
 * queda ninguna, y el marcado lleva las dos clases porque `credencial__curs`
 * sigue diciendo QUÉ es dentro de la tarjeta.
 */

/*
 * El marco del QR es el semáforo: verde vigente, rojo caducado. Nunca
 * comunica solo con color — el distintivo VÀLID / CADUCAT va siempre arriba.
 *
 * 15rem de ancho máximo no es una cifra estética, y es lo único de esta
 * tarjeta que no se puede encoger más. Con el token de 64 caracteres el QR
 * sale de 41 módulos, 45 contando la zona de silencio: a este tamaño cada
 * módulo ocupa unos 4,7 px de pantalla, que es lo que necesita la cámara de
 * un comercio a un palmo de distancia. En la referencia impresa el QR era un
 * adorno de esquina; a ese tamaño, en un móvil, deja de leerse.
 */
.carnet__marc {
  box-sizing: border-box;                /* 15rem es el tamaño de FUERA */
  width: 100%;
  max-width: 15rem;
  margin: 0 auto var(--afa-espai-3);
  background: var(--afa-blanc);
  border: 6px solid var(--afa-gris-300);
  border-radius: var(--afa-radi-m);
  padding: var(--afa-espai-2);
  transition: border-color .2s ease;
}

.carnet__marc--valid   { border-color: var(--afa-verd-600); }
.carnet__marc--caducat { border-color: var(--afa-vermell-600); }

/*
 * Sin carnet: el marco NO se pinta de ningún color de semáforo.
 *
 * Verde y rojo son un veredicto sobre una credencial, y aquí no hay
 * credencial sobre la que dar veredicto. Con el borde rojo, el previo se
 * seguiría leyendo como «te lo han denegado», que es justo lo que se está
 * corrigiendo. Se marca con un borde discontinuo, que es el lenguaje de «esto
 * es un hueco todavía por llenar» y no el de un estado.
 */
.carnet__marc--sense {
  border-style: dashed;
  border-color: var(--afa-gris-300);
  background: var(--afa-crema);
}

/* ── EL TABLERO: lo que ocupa el hueco del QR cuando no hay carnet ────────
 *
 * NO ES UN QR Y NO PUEDE PARECERLO. Ni siquiera se pone un código que lleve a
 * una página de «pendiente»: un cuadrado que se parece a un código invita a
 * que alguien lo escanee en un mostrador, y deja al comercio esperando una
 * respuesta que no va a llegar. Esto tiene que comunicar «todavía no hay
 * código» ANTES de que nadie levante el móvil.
 *
 * Por eso las casillas son de 2rem y no de 4 px. Un módulo de QR mide aquí
 * unos 4,7 px, así que estas son SEIS VECES más grandes; y no hay patrones de
 * posicionamiento en tres esquinas, que es lo que un lector busca primero.
 * Ninguna cámara va a intentar leer esto.
 */
.tauler {
  position: relative;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--afa-espai-3);
}

.tauler__dibuix {
  position: absolute;
  inset: 0;
  border-radius: var(--afa-radi-s);
  /* Dos degradados cruzados hacen el tablero sin ninguna imagen: cero
     peticiones, y escala a cualquier tamaño sin pixelarse. */
  background-color: var(--afa-blanc);
  background-image:
    linear-gradient(45deg, var(--afa-gris-100) 25%, transparent 25%, transparent 75%, var(--afa-gris-100) 75%),
    linear-gradient(45deg, var(--afa-gris-100) 25%, transparent 25%, transparent 75%, var(--afa-gris-100) 75%);
  background-size: 4rem 4rem;
  background-position: 0 0, 2rem 2rem;
}

/*
 * La etiqueta va sobre fondo opaco y no sobre el tablero: encima de las
 * casillas el contraste dependería de qué casilla le toque detrás, que es
 * justo la clase de medición que no se puede hacer. Sobre gris-100 el texto
 * en azul 900 da 13,65:1, y la pareja está en bin/contrast.php.
 */
.tauler__etiqueta {
  position: relative;
  /* Blanco con borde y no gris: el tablero ES gris claro sobre blanco, así
     que una etiqueta gris se funde con media casilla sí y media no, y se ve
     un recorte raro en el borde. Con el borde puesto, la etiqueta se lee como
     lo que es —una nota puesta encima— sobre las dos casillas. */
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  box-shadow: var(--afa-ombra-1);
  color: var(--afa-blau-900);
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  line-height: 1.35;
  text-align: center;
  border-radius: var(--afa-radi-s);
  padding: var(--afa-espai-2) var(--afa-espai-3);
}

/* La explicación completa, debajo de la tarjeta. `.nota` ya trae la marca
   circular con el símbolo del validador, así que no hace falta nada más. */
.carnet__sense { margin: 0 0 var(--afa-espai-4); text-align: left; }

.carnet__qr {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* El QR se dibuja en canvas: negro sobre blanco, sin filtros ni sombras que
   puedan estropear la lectura de la cámara del comercio. El ancho exacto lo
   fija app.js en píxeles para que cada módulo caiga sobre un número entero de
   píxeles físicos; aquí solo se impide que desborde si ese cálculo no ha
   llegado a ejecutarse. */
.carnet__qr canvas {
  max-width: 100%;
  height: auto;
  display: block;
  image-rendering: pixelated;
}

.carnet__carregant { color: var(--afa-text-suau); font-size: var(--afa-mida-s); }

/*
 * Distintivo de estado. El fondo y el símbolo viven en las variantes, no en
 * la clase base: mientras no hay veredicto el elemento está vacío, y una
 * píldora de color vacía en medio de la tarjeta es exactamente el (!) suelto
 * que ya nos pasó una vez.
 */
.carnet__estat {
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-molt);
  letter-spacing: .06em;
}

.carnet__estat--valid,
.carnet__estat--caducat,
.carnet__estat--sense {
  display: inline-flex;
  align-items: center;
  gap: var(--afa-espai-1);
  padding: 0.25rem 0.6rem 0.25rem 0.3rem;
  border-radius: 999px;
}

/* Marca circular con el mismo lenguaje de símbolos que el validador. El color
   nunca va solo: lleva símbolo y peso tipográfico. */
.carnet__estat--valid::before,
.carnet__estat--caducat::before,
.carnet__estat--sense::before {
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 0.75rem;
  line-height: 1;
  color: var(--afa-blanc);
}

.carnet__estat--valid {
  color: var(--afa-verd-600);
  background: var(--afa-verd-050);
}
.carnet__estat--valid::before {
  content: '\2713';                      /* ✓ */
  background: var(--afa-verd-600);
}

.carnet__estat--caducat {
  color: var(--afa-vermell-600);
  background: var(--afa-vermell-050);
}
.carnet__estat--caducat::before {
  content: '\2717';                      /* ✗ */
  background: var(--afa-vermell-600);
}

/*
 * PENDENT: ni verde ni rojo, porque no hay veredicto.
 *
 * Usa el tercer símbolo del validador, el «!», que es el que este proyecto ya
 * emplea para «esto hay que mirarlo» y no para «esto está mal». El fondo es
 * gris y no naranja a propósito: el naranja sobre blanco da 3,00:1 y esta
 * pastilla es texto pequeño, así que incumpliría AA — el mismo error que ya
 * se evitó en «Els meus usos». Sobre gris-100, el azul 900 da 13,65:1.
 */
.carnet__estat--sense {
  color: var(--afa-blau-900);
  background: var(--afa-gris-100);
}
.carnet__estat--sense::before {
  content: '!';
  background: var(--afa-blau-700);
  font-weight: var(--afa-pes-molt);
}

/*
 * ── LA CREDENCIAL, DISEÑO 2A (15 de septiembre) ──────────────────────────
 *
 * Portado del código fuente del handoff de Claude Design, no de las capturas:
 * los valores son los suyos, uno a uno.
 *
 * TODO LO QUE SE ESCRIBE SOBRE EL AZUL ESTÁ MEDIDO:
 *   blanco ............... 12,02:1   el nombre y los valores
 *   --afa-blau-200 ........ 5,58:1   las etiquetas, a 9,5px
 *   --afa-taronja-300 ..... 5,22:1   el antetítulo y el codi
 *
 * Y la vuelta de tuerca que esto resuelve: el naranja de marca sobre blanco da
 * 2,83:1 —por eso el título de la tarjeta vieja tuvo que subir de cuerpo en
 * agosto— y sobre este azul cualquiera de los dos naranjas pasa de sobra. El
 * fondo oscuro no es solo estética: es lo que libera el color de la casa.
 */

/* ── El antetítulo y el nombre ─────────────────────────────────────────── */
.credencial__tipus {
  position: relative;
  z-index: 1;
  margin: 0;
  color: var(--afa-taronja-300);
  font-size: 0.594rem;                   /* 9,5px */
  font-weight: var(--afa-pes-molt);
  letter-spacing: .14em;
  text-transform: uppercase;
}

.credencial__nom {
  position: relative;
  z-index: 1;
  margin: 3px 0 0;
  color: var(--afa-blanc);
  font-size: 1.0625rem;                  /* 17px */
  font-weight: var(--afa-pes-molt);
  letter-spacing: -.012em;
  /* Un nombre largo no puede empujar al ángulo ni partir la tarjeta. */
  overflow-wrap: anywhere;
}

/* ── El QR, en su caja blanca ──────────────────────────────────────────── */
.credencial .carnet__marc {
  position: relative;
  z-index: 1;
  max-width: none;                       /* 2A lo lleva a todo el ancho */
  margin: 15px 0 0;
  background: var(--afa-blanc);
  border: 0;
  border-radius: 1rem;                   /* 16px */
  padding: 13px;
}

/*
 * EL BORDE DE SEMÁFORO SE VA DE AQUÍ. Era un aro verde o rojo alrededor del
 * QR, y en 2A el veredicto lo lleva la pastilla del pie. Dos sitios diciendo
 * lo mismo es uno de más — y el aro de color alrededor de un código reduce su
 * zona de silencio, que es justo lo que una cámara necesita.
 */
.credencial .carnet__marc--valid,
.credencial .carnet__marc--caducat { border: 0; }

.credencial .carnet__marc--sense {
  background: rgba(255, 255, 255, .08);
  border: 1px dashed rgba(255, 255, 255, .35);
}

/* ── Las dos columnas ──────────────────────────────────────────────────── */
.credencial__graella {
  position: relative;
  z-index: 1;
  margin-top: 15px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.credencial__camp {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.credencial__et {
  color: var(--afa-blau-200);            /* 5,58:1 */
  font-size: 0.594rem;                   /* 9,5px */
  letter-spacing: .08em;
  text-transform: uppercase;
}

.credencial__val {
  color: var(--afa-blanc);               /* 12,02:1 */
  font-size: 0.875rem;                   /* 14px */
  font-weight: var(--afa-pes-molt);
}

/* El número de socia se dice EN VOZ ALTA por teléfono: monoespaciada. */
.credencial__val--mono { font-family: var(--afa-mono); }

/* ── El pie: el codi y el veredicto, juntos ────────────────────────────── */
.credencial__peu {
  position: relative;
  z-index: 1;
  margin-top: 13px;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, .16);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.credencial__camp--codi { flex: 1 1 auto; }

.credencial .codi {
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  /*
   * SOLO EL CÓDIGO ES TOCABLE, no toda la fila. `.credencial__camp` es una
   * columna flexible, así que el botón se BLOQUIFICA y ocupa todo el ancho:
   * tocando el hueco vacío de la derecha también se copiaba. Con
   * `align-self: start` el botón mide lo que mide el código.
   */
  align-self: start;
  color: var(--afa-taronja-300);         /* 5,22:1 */
  font-family: var(--afa-mono);
  font-size: 0.75rem;                    /* 12px */
  font-weight: var(--afa-pes-molt);
  cursor: pointer;
}

/* ── La pastilla del veredicto ─────────────────────────────────────────── */
/*
 * ── LA PASTILLA TÉ L'AMPLADA DE LA DATA, I NO LA DEL SEU TEXT ───────────
 *
 * Decisió de David del 20 de setembre de 2026, i el número no és inventat:
 * **«30/08/2026» ocupa 89,92 px** amb el cos i el pes de `.credencial__val`,
 * mesurat al navegador contra el que serveix el servidor. Són els 5,29rem
 * d'aquí sota, sobre l'arrel de 17px.
 *
 * Amb això la pastilla i la data queden UNA SOTA L'ALTRA i comparteixen el
 * caire dret. L'amplada deixa de ser un número triat i passa a ser una
 * alineació, que és el que fa que no sembli una càpsula estirada.
 *
 * ── I PER QUÈ FIXA I NO UN MÍNIM ────────────────────────────────────────
 *
 * Perquè els tres estats han de mesurar el mateix: si «CADUCAT» fos més ample
 * que «VÀLID», el caire dret ballaria segons com estigui la quota, que és
 * justament el dia que la família mira la targeta amb atenció.
 *
 * Hi caben tots tres, mesurat: CADUCAT demana 73,9px i li queden 8 a cada
 * costat. El dia que algú vulgui un text més llarg, aquí es trencarà — i
 * s'ha de trencar aquí i no a la pantalla d'algú: hi ha prova que ho afirma.
 */
.credencial .carnet__estat {
  flex: none;
  border-radius: 999px;
  /*
   * Sense farciment lateral: l'amplada ja està donada i el text va centrat.
   * Amb farciment, el text es descentraria respecte de la càpsula el dia que
   * la paraula canviï de llargada.
   */
  width: 5.29rem;                        /* 89,92px: el que ocupa «30/08/2026» */
  padding: 5px 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 0.875rem;                   /* el mateix cos que la validesa */
  font-weight: var(--afa-pes-molt);
  letter-spacing: .08em;
}
.credencial .carnet__estat--valid   { background: var(--afa-verd-valid);  color: var(--afa-blanc); }
.credencial .carnet__estat--caducat { background: var(--afa-vermell-600); color: var(--afa-blanc); }
.credencial .carnet__estat--sense   { background: rgba(255,255,255,.14);  color: var(--afa-blanc); }

/* ── La versión, ya fuera de la tarjeta ────────────────────────────────── */
.credencial__versio {
  position: static;
  margin: var(--afa-espai-2) 0 0;
  text-align: right;
  color: var(--afa-calid-600);           /* desviación medida: 4,51:1 */
  font-family: var(--afa-mono);
  font-size: 0.594rem;
  letter-spacing: .02em;
  -webkit-text-stroke: 0;
}

/*
 * El código de descuento es UNA FILA MÁS.
 *
 * Decisión de David, y tenía razón: misma tipografía, mismo tamaño y misma
 * estructura que el titular, el número de socia y la validez. La cohesión de
 * la tarjeta manda sobre cualquier ganancia de legibilidad del código.
 *
 * Mi primera versión lo puso en monoespaciada y con las letras separadas "para
 * que se lea mejor". Dos problemas: rompía la unidad visual de la tarjeta, y era
 * ANCHO — diecisiete caracteres monoespaciados más la etiqueta no caben en
 * 375px, así que el código se partía en dos y hubo que darle una fila propia.
 * En proporcional cabe de sobra en una línea: el arreglo de David resuelve las
 * dos cosas a la vez.
 *
 * Y la legibilidad no se pierde donde importaba: el alfabeto ya excluye la I,
 * la L, la O y la U precisamente para que no haga falta una tipografía especial
 * que distinga el 1 de la l ni el 0 de la O.
 *
 * Lo único que lo distingue de un valor normal es el subrayado punteado, que es
 * la pista de que se puede tocar para copiar: una señal de comportamiento, no
 * un cambio de tipografía.
 */
.codi {
  font-family: inherit;
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-fort);
  color: var(--afa-blau-900);
  letter-spacing: normal;

  display: inline;
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  border-bottom: 1px dotted var(--afa-vora);
  transition: color .2s ease, border-color .2s ease;
}
/*
 * ── EL CÓDIGO QUE «DESAPARECÍA»: ERA ESTE `:hover` ───────────────────────
 *
 * David: «cuando "Copiat" se desvanece, el código desaparece y no se ve». No
 * desaparecía: se quedaba pintado a **1,03:1**.
 *
 * `--afa-primari` es `--afa-blau-700` (#1B3A5C) y la credencial es
 * `--afa-marina` (#16385A). Son el mismo azul. Esta regla se escribió cuando
 * la tarjeta era CLARA, y el diseño 2A la volvió marina sin que nadie la
 * repasara — la tercera vez que un color del carnet blanco se queda pintando
 * sobre el carnet oscuro, después del enlace de la cabecera.
 *
 * Y por eso solo se veía DESPUÉS de tocar: `.codi:hover` (0,2,0) llega
 * después de `.credencial .codi` (0,2,0) en este mismo fichero, así que gana;
 * y **en una pantalla táctil el `:hover` se queda pegado** tras el toque hasta
 * que tocas otra cosa. Tocar para copiar equivalía a apagar el código.
 *
 * `@media (hover: hover)` es el arreglo de fondo y vale para todo el
 * proyecto: un aparato sin ratón NO entra nunca en este bloque, así que
 * ningún `:hover` se le puede quedar clavado. Dentro de la tarjeta, además,
 * el color de realce es uno que se ve sobre marino.
 */
@media (hover: hover) {
  .codi:hover { color: var(--afa-primari); border-bottom-color: var(--afa-primari); }
  /*
   * EL REALCE ACLARA, no cambia de familia. `--afa-taronja-500` sobre la
   * marina da **4,00:1** —medido, y la puerta lo rechazó— así que va el 200,
   * que es el mismo naranja lavado y llega a 8,60. Con ratón, lo único que
   * tiene que decir es «esto se puede tocar».
   */
  .credencial .codi:hover { color: var(--afa-taronja-200); border-bottom-color: currentColor; }
}
.codi:focus-visible { outline: 2px solid var(--afa-accent); outline-offset: 3px; }

/*
 * ── LA CONFIRMACIÓN DE COPIADO ───────────────────────────────────────────
 *
 * Tres cosas medidas, y las tres estaban mal en la tarjeta del carnet:
 *
 * 1. `display: block` dentro de un botón `inline` AÑADE UNA LÍNEA: el botón
 *    pasaba de 15 a 31 px al tocar el código, así que el pie de la credencial
 *    crecía y la píldora del veredicto saltaba de sitio. Ahora va en línea y
 *    `:empty` la retira del todo cuando no dice nada — sin eso, un hueco
 *    vacío sigue ocupando su margen.
 *
 * 2. `--afa-verd-600` sobre la credencial marina da **2,26:1**. O sea que la
 *    palabra «Copiat» era casi invisible justo donde más se toca el código.
 *    En la tarjeta va `--afa-verd-300` (6,86:1); fuera, sobre blanco, el 600
 *    sigue siendo el correcto.
 *
 * 3. `.codi--copiat` (0,1,0) nunca ganaba a `.credencial .codi` (0,2,0), así
 *    que el código tampoco se teñía. Se retira el cambio de color del BOTÓN:
 *    la señal es la palabra, que es la que funciona sin color — y así no hay
 *    dos reglas peleándose por el mismo píxel.
 */
.codi--copiat { border-bottom-color: currentColor; }
.codi__estat {
  display: inline;
  margin-left: .45em;
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  color: var(--afa-verd-600);
}
.codi__estat:empty { display: none; }
.credencial .codi__estat { color: var(--afa-verd-300); }   /* 6,86:1 */

/*
 * SI NO CABE, EL CÓDIGO PARTE POR UN GUION, y eso hoy no lo escribe ninguna
 * regla: es el comportamiento por defecto del navegador, que ya trata el guion
 * como una oportunidad de corte. Hubo una línea que lo forzaba
 * (`overflow-wrap: normal`) mientras el código vivía en una celda de rejilla
 * con `min-width: 0`, donde el defecto no bastaba; con la credencial de 2A esa
 * celda desapareció. Queda escrito porque la regla que importa es la de al
 * lado: **nunca se recorta ni se rompe por la mitad de un grupo**. En un móvil
 * de 320 es mejor "AFA67-" / "BZ3QS-M9Q97" que perder dos caracteres.
 */
/*
 * ── AQUÍ HI HAVIA LA CAMPANA I LA HAMBURGUESA DE LA CAPÇALERA ───────────
 *
 * `.icona`, el seu objectiu tàctil de 44x44, i `.icona__comptador`, el número
 * que anava damunt de la campana. El disseny 2A se'ls va endur: «Avisos» és
 * una pestanya de la barra amb el seu punt, i el que obria la hamburguesa ara
 * el obre la pestanya «Compte». Feia dies que no els pintava ningú.
 */

/* ── Menú desplegable ────────────────────────────────────────────────────── */
/*
 * EL FULL DEL COMPTE — antes era el desplegable de la hamburguesa.
 *
 * Cambia de sitio porque cambió su disparador: colgaba de un botón de la
 * esquina superior derecha y ahora lo abre la pestaña «Compte» de la barra
 * inferior. Un panel que se abre arriba desde un botón de abajo obliga a
 * cruzar la pantalla con la vista y deja el dedo tapando justo lo que se
 * acaba de abrir.
 *
 * Sube DESDE LA BARRA y se queda al alcance del pulgar, que es la idea entera
 * de 2A: «res tapa el carnet, els xips s'aixequen des de baix».
 */
.menu {
  position: fixed;
  /*
   * ── ACABA DONDE EMPIEZA LA BARRA, NO EN EL SUELO ──────────────────────
   *
   * Esto estaba en `bottom: 0` con un relleno inferior de la altura de la
   * barra, con la idea de «dejarla libre». No la dejaba: el relleno aparta el
   * CONTENIDO, pero el fondo blanco de la hoja se pinta igual y la hoja está
   * por encima (z-index 21 contra 20). O sea que al abrir «Compte» la barra
   * desaparecía debajo de un rectángulo blanco — lo vio David.
   *
   * Ahora la hoja termina donde empieza la barra, que además es lo que dice
   * el diseño 3B: las píldoras se LEVANTAN desde la barra, no la tapan.
   *
   * El atajo primero y la medida frágil en su longhand aparte, la regla de
   * siempre: si Safari no parsea `env()` dentro de un `calc()`, lo peor que
   * pasa es que la hoja se quede en la altura de la barra sin el recorte.
   */
  inset: auto 0 0 0;
  /*
   * ── LA BARRA PINTA POR ENCIMA, Y ASÍ NO HACE FALTA SABER CUÁNTO MIDE ──
   *
   * El intento anterior levantaba la hoja `--afa-barra-alt` sobre el suelo, y
   * quedaba flotando: esa variable son los 5,25 rem de HUECO que antes hacía
   * sitio a la barra fija, no su altura real. Cualquier número escrito aquí
   * sería un número que hay que acordarse de cambiar el día que la barra
   * cambie de cuerpo — y ya sabemos cómo acaba eso.
   *
   * Así que la hoja sube desde el suelo y **la barra se pinta encima** (20
   * contra 19). Lo que queda a la vista es exactamente la barra, sin que nadie
   * mida nada, y el relleno inferior mantiene el CONTENIDO de la hoja por
   * encima de ella. Es lo que la versión original pretendía; lo que tenía mal
   * era el orden de apilado.
   *
   * Y de paso la barra sigue siendo tocable con la hoja abierta: tocar otra
   * pestaña cierra el full y navega, que es lo que uno espera.
   */
  z-index: 19;
  background: var(--afa-blanc);
  border: 0;
  border-top: 1px solid var(--afa-calid-100);
  border-radius: var(--afa-radi-l) var(--afa-radi-l) 0 0;
  box-shadow: 0 -12px 34px rgba(16, 36, 58, .18);
  /* El atajo primero y la medida frágil en su longhand aparte, la de siempre. */
  padding: var(--afa-espai-4) var(--afa-espai-3) 5.25rem;
  padding-bottom: calc(5.25rem + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  gap: var(--afa-espai-1);
  max-height: 80vh;
  overflow-y: auto;
}

@media (min-width: 64rem) {
  /* En escritorio no hay barra inferior: vuelve a ser el desplegable de antes. */
  .menu {
    position: absolute;
    inset: 100% var(--afa-espai-3) auto auto;
    min-width: 12rem;
    border: 1px solid var(--afa-vora);
    border-radius: var(--afa-radi-m);
    box-shadow: var(--afa-ombra-2);
    padding: var(--afa-espai-2);
    max-height: none;
  }
}

/*
 * ── L'ENCAPÇALAMENT DE GRUP D'AQUEST FULL TAMPOC HI ÉS JA ────────────────
 *
 * `.menu__grup` i la píndola del rol `.menu__rol` vestien els títols «El meu
 * carnet» i «Gestió» del full del «Compte». Des que la barra es va quedar
 * «Gestió», el full no pot tenir mai dos grups, així que el títol era un
 * títol solitari damunt d'una sola llista i `menuOpcions()` ha deixat
 * d'escriure'l. El lateral d'escriptori té els seus (`.lateral__grup`), que
 * allà sí que separen dues coses.
 */

/*
 * Las opciones son ahora ENLACES además de botones (las secciones vienen de
 * `Disseny::menuOpcions()`), y un `<a>` de bloque con `min-height` deja el
 * texto pegado arriba mientras un `<button>` lo centra solo. Con flex se
 * comportan igual los dos, que es lo que hay que pedirle a una lista donde
 * conviven.
 */
/*
 * El hueco del icono se reserva SIEMPRE, también en las dos opciones que no
 * lo llevan («Com instal·lar l'app» y «Tanca la sessió», que son botones y no
 * secciones). Sin eso, sus etiquetas quedarían media pulgada a la izquierda
 * de las demás y la lista se leería torcida. Es la misma decisión que el
 * hueco del triángulo en la barra lateral.
 */
/*
 * AQUESTA REGLA ES DECLARAVA DUES VEGADES EN AQUEST MATEIX FULL, i la de sota
 * —la del disseny— en pisava gairebé tot. El que quedava viu d'aquí eren dues
 * línies (`min-height` i `font-family`), i s'han mudat allà. Mentre les dues
 * hi eren, llegir qualsevol de les dues no deia com es pinta la píndola: va
 * ser exactament el que va deixar `.capcalera` a 1,08:1.
 */
.menu__opcio:focus-visible { outline: 3px solid var(--afa-accent); outline-offset: -2px; }

/* ── Guía de instalación ─────────────────────────────────────────────── */
.carnet__accions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--afa-espai-2);
  margin-top: var(--afa-espai-6);
}

.carnet__avis-push {
  margin: var(--afa-espai-5) 0 0;
}

/*
 * ── UN VELO Y UNA CAJA: UNA SOLA DECLARACIÓN, DOS NOMBRES ────────────────
 *
 * `.capa` es la guía de instalación y `.desc__full` es la ficha del comercio
 * que se abre desde el mosaico de Descomptes. **Son el mismo objeto**: un
 * diálogo modal, con velo, que en el móvil sube desde abajo y a partir de
 * 40rem se centra. Copiar las nueve líneas del velo y las siete de la caja
 * habría sido el fallo de siempre — la que se toca y la que se olvida — y
 * aquí muerde más fuerte que de costumbre, porque lo que se olvidaría es el
 * `z-index: 30` o el `max-height` que evita que la caja se salga de un
 * teléfono corto.
 *
 * Es el mismo movimiento que `.menu__opcio, .g__full-opcio` en tokens.css y
 * que `.avisos, .llista` unas líneas más abajo: la PIEL compartida en un
 * sitio, y las diferencias de cada uno en su bloque.
 *
 * Lo propio de la ficha del comercio —la esquina de cierre, la marca, el
 * descuento grande— vive al final de esta hoja, en su sección.
 */
.capa,
.desc__full {
  position: fixed;
  inset: 0;
  background: var(--afa-vel);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: var(--afa-espai-4);
  /*
   * POR ENCIMA DE TODO, que es lo que es: un diálogo modal con velo. Estaba en
   * 10, o sea POR DEBAJO de la barra (20) y del full del Compte (19), así que
   * la navegación se pintaba sobre el velo. La escala del proyecto es:
   * contenido · full 19 · barra 20 · modal 30.
   */
  z-index: 30;
}

/*
 * ── LA FITXA D'UN COMERÇ VA CENTRADA, NO ENGANXADA A BAIX ────────────────
 *
 * `.capa` neix com un full que puja des del terra, i per a la guia d'instal·lar
 * està bé: allò és una seqüència de passos i el dit ja hi és a sota.
 *
 * Per a la fitxa d'un comerç no ho està, i ho va patir David en un iPhone: la
 * caixa fa uns 460px i, enganxada a baix, l'última fila —justament «Com
 * arribar-hi»— queda damunt de la **barra d'inici del telèfon**. En prémer-la
 * el sistema se l'emporta a l'escriptori. No és una molèstia estètica: és un
 * enllaç que et fa fora de l'aplicació.
 *
 * Centrada, la caixa queda entre 190 i 650 en una pantalla de 844, que és a
 * 190px de la barra. I si algun dia el contingut creix fins al màxim (85vh),
 * segueix quedant-ne 64 per sota.
 *
 * ── EL COIXÍ DE BAIX VA EN PROPIETAT LLARGA, I NO ÉS UN CAPRICI ──────────
 *
 * `padding-bottom` i no el `padding` abreujat: aquest projecte ja va pagar que
 * Safari **tira les QUATRE mesures** quan una d'elles porta `max()` amb `env()`
 * a dins d'un atajo. Escrita a part, si el navegador no entén `env()` es queda
 * amb la de dalt i no perd les altres tres.
 */
.desc__full {
  align-items: center;
  padding-bottom: max(var(--afa-espai-4), env(safe-area-inset-bottom));
}

.capa__caixa,
.desc__full-caixa {
  background: var(--afa-blanc);
  border-radius: var(--afa-radi-l);
  padding: var(--afa-espai-5);
  width: 100%;
  max-width: 26rem;
  box-shadow: var(--afa-ombra-2);
  /* Con el teclado o en pantallas cortas, el diálogo hace scroll él mismo. */
  max-height: 85vh;
  overflow-y: auto;
}

.capa__titol {
  font-size: var(--afa-mida-l);
  font-weight: var(--afa-pes-molt);
  margin: 0 0 var(--afa-espai-2);
}

.capa__intro {
  color: var(--afa-text-suau);
  font-size: var(--afa-mida-s);
  margin: 0 0 var(--afa-espai-4);
}

.capa__passos {
  margin: 0 0 var(--afa-espai-4);
  padding-left: var(--afa-espai-5);
  line-height: 1.6;
}

.capa__passos li { margin-bottom: var(--afa-espai-3); }

.capa__avis { margin: 0 0 var(--afa-espai-4); }

@media (min-width: 40rem) {
  .capa,
  .desc__full { align-items: center; }
}

/* ── Los pasos de iOS, con los iconos dibujados ──────────────────────────
   Se dibujan porque «el quadre amb la fletxa cap amunt» obliga a traducir
   una frase a un icono mientras se mira una barra llena de iconos. */
.capa__passos--dibuixats li { margin-bottom: var(--afa-espai-4); }

.pas__text     { display: block; }
.pas__nota     {
  display: block;
  margin-top: var(--afa-espai-1);
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
}

.pas__mostra {
  display: flex;
  align-items: center;
  gap: var(--afa-espai-2);
  margin-top: var(--afa-espai-2);
}

/* Cuadrito con el símbolo, del tamaño real al que se ve en la barra. */
.pas__icona {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--afa-radi-m);
  background: var(--afa-gris-100);
  color: var(--afa-primari);
  flex: 0 0 auto;
}

/*
 * La flecha que bota.
 *
 * SEÑALA AL DIBUJO Y NO A UN BORDE DE LA PANTALLA, porque no hay forma de
 * saber si la barra de Safari está arriba o abajo (es configurable desde
 * iOS 15 y ninguna API lo expone). Apuntar al borde equivocado es peor que
 * no apuntar.
 *
 * El movimiento lo apaga la regla global de `prefers-reduced-motion` de
 * tokens.css, que reduce toda animación a 0,01 ms: la flecha se queda quieta
 * en su sitio y sigue señalando, que es justo lo que tiene que pasar. Por eso
 * la animación mueve la flecha y no la hace aparecer.
 */
.pas__fletxa {
  display: inline-flex;
  color: var(--afa-accent);
  animation: afa-assenyala 1.2s ease-in-out infinite;
}

@keyframes afa-assenyala {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(.4rem); }
}

/* Imitación de la fila de la hoja de compartir de iOS. */
.pas__fila {
  display: flex;
  align-items: center;
  gap: var(--afa-espai-3);
  margin-top: var(--afa-espai-2);
  padding: var(--afa-espai-2) var(--afa-espai-3);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
}

.pas__etiqueta { font-size: var(--afa-mida-s); }

/* Qué se pierde sin instalar. Va al final y en tono bajo: se informa, no se
   presiona — el QR no se condiciona nunca a instalar nada. */
.capa__perdua {
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
  line-height: 1.5;
  margin: 0 0 var(--afa-espai-4);
}


/* ── El puente al móvil (solo escritorio) ────────────────────────────────
   No se pinta nunca en un móvil: lo revela app.js, así que en 375 px este
   bloque no existe y no puede empeorar la pantalla que sí funciona. */
.pont {
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
  padding: var(--afa-espai-5);
  margin-top: var(--afa-espai-6);
  text-align: center;
  box-shadow: var(--afa-ombra-1);
}

.pont__titol {
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-molt);
  margin: 0 0 var(--afa-espai-2);
}

.pont__cos {
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  line-height: 1.5;
  margin: 0 0 var(--afa-espai-4);
}

/* El ancho del canvas lo fija app.js en píxeles enteros, igual que el del
   carnet: con un 100% el navegador escala por un factor cualquiera y hay
   cámaras que dejan de leer el código. Aquí solo se centra. */
.pont__qr {
  display: flex;
  justify-content: center;
  margin-bottom: var(--afa-espai-4);
}

.pont__adreca {
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
  margin: 0;
}

.pont__url {
  display: block;
  margin-top: var(--afa-espai-1);
  font-family: var(--afa-font-mono);
  font-size: var(--afa-mida-s);
  color: var(--afa-primari);
  word-break: break-all;
}


/* ── La entrada, en escritorio ───────────────────────────────────────────
 *
 * La pantalla de entrada es lo primero que ve una familia que abre el enlace
 * en el portátil, y era la única del portal que se había quedado sin mirar
 * en ancho: una columna de 24 rem centrada en 1.440 px con el reclamo del
 * móvil debajo, apretado a esa misma medida. El QR salía pequeño, el texto
 * partía en líneas de cinco palabras y la dirección se rompía a media
 * palabra («carnet.afa.deivi / d.net»), porque `.pont__url` tiene
 * `word-break: break-all` — que es lo correcto en un móvil y ridículo en una
 * columna que sobra por todos lados.
 *
 * Se resuelve con la maqueta y no tocando ninguna de esas reglas: en ancho,
 * el formulario y el puente al móvil van uno al lado del otro. Es el mismo
 * reparto que el resumen hace con su banda azul —lo que se lee a un lado, lo
 * que se hace al otro— y el mismo que hacen MoMA y Tate: la web fabrica, el
 * móvil porta.
 *
 * Todo va dentro de la media query de 64 rem, así que en el móvil no cambia
 * ni un píxel: la pantalla de entrada sigue siendo una columna.
 */
@media (min-width: 64rem) {
  /*
   * ── LA GRAELLA NOMÉS EXISTEIX SI EL PONT HI ÉS ──────────────────────────
   *
   * Això és una reparació, i d'un fallo meu. En apagar el pont, la graella es
   * va quedar: dues columnes de les quals la segona era buida, així que el
   * formulari quedava arraconat a l'esquerra d'una caixa de 48rem en una
   * finestra de 1440. David ho va veure de seguida: *«en Desktop es
   * horrible»*.
   *
   * La lliçó, que és la que val: **apagar una peça no és només amagar-la; és
   * treure-la d'on la comptava algú altre.** La maqueta d'aquesta pantalla
   * existeix PER al pont, i s'havia escrit com si el pont hi fos sempre.
   *
   * Amb `:has()` la maqueta segueix el contingut en lloc de suposar-lo: dues
   * columnes quan hi ha pont visible, una columna centrada quan no. I el dia
   * que es torni a engegar, la graella torna sola — no hi ha cap segon
   * interruptor del qual algú s'hagi de recordar.
   */
  #vista-login .login:has(.pont:not([hidden])) {
    max-width: 48rem;
    display: grid;
    grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    column-gap: var(--afa-espai-7);
    align-items: start;
  }

  /*
   * TODO LO DEMÁS SE FIJA A LA PRIMERA COLUMNA, y esto no es defensivo: sin
   * ello la colocación automática va rellenando fila por fila y, en cuanto
   * el puente ocupa la celda (1,2), el título se cuela en (2,2) y el
   * formulario en (3,1) — el formulario de entrada partido en dos columnas.
   * Visto en pantalla, no razonando sobre la rejilla.
   */
  #vista-login .login:has(.pont:not([hidden])) > * { grid-column: 1; }

  /* El envoltorio del formulario ocupa la primera columna entera; el reclamo
     del móvil, la segunda. Dos hijos y dos columnas: nada que colocar a
     mano y nada que se descoloque al añadir un campo. */
  #vista-login .login:has(.pont:not([hidden])) .login__cos { grid-column: 1; grid-row: 1; }

  /* El puente va en la segunda columna y en la primera fila, para que su
     tarjeta empiece a la altura del logotipo y no a la del botón. */
  #vista-login .pont:not([hidden]) {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
  }
}

/* ── Tarjeta de primera vez para los avisos ──────────────────────────────
   Visible y explicada, no un enlace discreto: el permiso del navegador se
   puede pedir una sola vez, así que conviene que la familia entienda para
   qué antes de decidir. */
.targeta {
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
  padding: var(--afa-espai-5);
  margin-top: var(--afa-espai-6);
  text-align: left;
  box-shadow: var(--afa-ombra-1);
}

.targeta__titol {
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-molt);
  margin: 0 0 var(--afa-espai-2);
}

.targeta__cos {
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  line-height: 1.5;
  margin: 0 0 var(--afa-espai-4);
}

.targeta__accions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--afa-espai-3);
}

.targeta__accions .boto--primari { width: auto; margin-top: 0; }

/* Variante destacada: va encima del QR y tiene que verse a la primera. */
.targeta--destacada {
  background: var(--afa-blau-700);
  border: 0;
  color: var(--afa-blanc);
  margin: 0 0 var(--afa-espai-5);
}

.targeta--destacada .targeta__titol { font-size: var(--afa-mida-l); }
.targeta--destacada .targeta__cos   { color: var(--afa-blanc); opacity: .9; margin-bottom: var(--afa-espai-3); }

.targeta__llista {
  margin: 0 0 var(--afa-espai-3);
  padding-left: var(--afa-espai-5);
  font-size: var(--afa-mida-s);
  line-height: 1.6;
}

.targeta__llista li { margin-bottom: var(--afa-espai-1); }

.targeta__promesa {
  font-size: var(--afa-mida-xs);
  opacity: .85;
  margin: 0 0 var(--afa-espai-4);
}

/* Sobre el azul, el botón principal va en naranja con texto azul oscuro:
   5,24:1 comprobado. Blanco sobre naranja daría 3,00 y no vale. */
.targeta--destacada .boto--primari {
  background: var(--afa-accent);
  color: var(--afa-blau-900);
}

.targeta--destacada .boto--text { color: var(--afa-blanc); }


/* ── Sección de avisos ───────────────────────────────────────────────────── */


/*
 * `.llista` es el mismo contenedor que `.avisos`, con otro nombre.
 *
 * Se declara aquí junto y no copiado abajo porque duplicar los números
 * (el ancho, el hueco, el relleno) es lo que hace que dos pantallas se
 * separen sin que nadie lo decida. Duplicar presentación cuesta trabajo;
 * duplicarla MAL cuesta que el proyecto parezca dos proyectos.
 */
.avisos,
.llista {
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--afa-espai-5) var(--afa-espai-4) var(--afa-espai-7);
  display: flex;
  flex-direction: column;
  gap: var(--afa-espai-3);
}

/*
 * EN ANCHO, EL CONTENIDO SE ALINEA CON SU TÍTULO.
 *
 * `margin: 0 auto` centra estas listas dentro de la columna de contenido, y
 * eso era lo correcto cuando la columna medía lo mismo que la lista. Con la
 * barra lateral, la columna mide 900 px y la lista 578: el `<h1>` quedaba a
 * la izquierda del todo y el texto empezaba 200 px más adentro, así que la
 * pantalla parecía dos pantallas mal pegadas.
 *
 * Se mantiene la MEDIDA de 34 rem, que es la que hace legible una línea de
 * prosa (Baymard: 50-75 caracteres; por encima de eso la gente evita leer).
 * Lo que se quita es el centrado, que es otra cosa.
 *
 * El corte es el mismo 64 rem de siempre —donde aparece la barra lateral—,
 * y por debajo no cambia nada: en compacto la columna y la lista vuelven a
 * medir lo mismo y centrar es lo correcto.
 */
@media (min-width: 64rem) {
  .avisos,
  .llista {
    margin-inline: 0;
    padding-inline: 0;
  }
}

.avis-item,
.fitxa {
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
  padding: var(--afa-espai-4);
}

/*
 * Sin leer: fondo levemente teñido y el TRIÁNGULO del logotipo delante del
 * título — la muntanya, el motivo de la casa. Nada de franja lateral.
 * El color nunca es la única señal: va con la forma y con el peso del título.
 */
.avis-item--nou {
  background: var(--afa-taronja-050);
  border-color: var(--afa-taronja-500);
}

.avis-item--nou .avis-item__titol::before {
  content: '';
  display: inline-block;
  width: 0.72em;
  height: 0.62em;
  margin-right: 0.45em;
  background: var(--afa-taronja-500);
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.avis-item__titol {
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-fort);
  margin: 0 0 var(--afa-espai-1);
}

.avis-item--nou .avis-item__titol { font-weight: var(--afa-pes-molt); }

.avis-item__cos {
  font-size: var(--afa-mida-s);
  color: var(--afa-text);
  line-height: 1.5;
  margin: 0 0 var(--afa-espai-2);
}

.avis-item__data {
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
  margin: 0;
}

.avisos__buit {
  text-align: center;
  color: var(--afa-text-suau);
  font-size: var(--afa-mida-s);
  line-height: 1.6;
  padding: var(--afa-espai-7) var(--afa-espai-4);
}


/* ── Els meus usos i les meves sessions ──────────────────────────────────── */
.llista { padding-bottom: 0; }
.llista__peu { padding-top: var(--afa-espai-4); align-items: center; }

/*
 * El subtítol: què s'hi fa, a sota del títol de la pantalla. Va en la tinta
 * forta i no en la suau perquè NO és una explicació: és l'acció.
 */
.llista__subtitol {
  margin: 0 0 var(--afa-espai-1);
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-fort);
  color: var(--afa-text);
}

.llista__intro {
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  line-height: 1.5;
  margin: 0;
}

.llista__resum {
  font-size: var(--afa-mida-s);
  color: var(--afa-text);
  margin: var(--afa-espai-2) 0 0;
}

.llista__resum strong { font-weight: var(--afa-pes-molt); }

/*
 * La ficha de un uso: fecha a la izquierda, resultado a la derecha.
 *
 * El resultado NO se marca solo con color. Lleva la marca circular con el
 * símbolo del validador (✓ · ! ) —el recurso propio del proyecto— para que
 * quien no distingue verde de rojo lea lo mismo.
 */
.fitxa {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--afa-espai-3);
}

/*
 * ── UN CORREU LLARG SE'N PORTAVA LA PANTALLA ────────────────────────────
 *
 * Trobat mesurant la capçalera de «La meva família» a 375px: amb el correu
 * `maria.antonia.garcia.puig@gmail.com` —que no té res d'extraordinari— la
 * pàgina passava a amidar **427px**, o sigui 52 de scroll horitzontal en un
 * iPhone. A 320 eren 107. NO ve del botó: la targeta ja ho feia abans, i es
 * veu perquè la pastilla «Sóc jo» surt tallada pel caire dret.
 *
 * LA CAUSA ÉS LA DE SEMPRE AMB FLEXBOX, i val la pena tenir-la escrita: un
 * element flex NO s'encongeix per sota del seu contingut mínim, perquè
 * `min-width` val `auto` per defecte. Un correu no té cap punt on partir-se,
 * així que el seu mínim és la cadena sencera i el bloc empeny la targeta
 * enfora. `max-width` a la llista no salva res: qui desborda és el fill.
 *
 * Tres propietats i cadascuna fa una cosa: `min-width: 0` als fills deixa
 * que s'encongeixin de veritat, `overflow-wrap: anywhere` al correu li dona
 * on partir-se, i `flex: none` a la pastilla fa que qui cedeixi sigui el
 * correu i no l'estat.
 *
 * LES DUES ÚLTIMES VAN DINS DE LES DECLARACIONS QUE JA EXISTEIXEN, unes
 * línies més avall, i no en blocs nous aquí al costat. Ho va parar la prova
 * de `bin/proves/disseny.php` que compta classes declarades dues vegades:
 * amb dos blocs amb el mateix nom, llegir-ne un no diu com es pinta. És la
 * mateixa regla que va deixar `.g__grup` significant dues coses.
 */
.fitxa > * { min-width: 0; }

.fitxa__data {
  font-size: var(--afa-mida-s);
  color: var(--afa-text);
  margin: 0;
}

.fitxa__detall {
  display: block;
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
  margin-top: 2px;
}

.fitxa__estat {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  /* El que ha de cedir és el correu, no l'estat. Ver `.fitxa > *`. */
  flex: none;
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  /*
   * AQUESTA SÍ QUE PORTA `nowrap`, i s'hi queda: els seus textos són «Sóc jo»,
   * «Vàlid», «Caducat» — cap no desborda res. Qui se sortia de la targeta era
   * `.fitxa__etiqueta`, que és una altra. Ho vaig arreglar primer aquí per
   * haver llegit el full en lloc de mirar la pantalla: el nom de la classe
   * només es veu inspeccionant l'element.
   */
  white-space: nowrap;
  color: var(--afa-text);
}

.fitxa__estat::before {
  content: '';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25em;
  height: 1.25em;
  border-radius: 50%;
  font-size: 0.85em;
  font-weight: var(--afa-pes-molt);
  line-height: 1;
}

/*
 * EL TEXTO DE LOS TRES ESTADOS VA EN EL COLOR DEL TEXTO NORMAL, no en el color
 * del estado. A `--afa-mida-xs` el naranja de la paleta sobre blanco da 3.00:1
 * y WCAG pide 4.5 para texto pequeño — el 3.0 solo vale para texto grande, que
 * es lo que ya está anotado para el título de la tarjeta. Pintarlo de naranja
 * aquí habría incumplido AA en la pantalla que más se lee de las dos.
 *
 * La diferencia entre estados la lleva la MARCA CIRCULAR: símbolo distinto
 * (los mismos ✓ · ! del validador), tinte distinto y peso distinto. Es la
 * regla de la casa: el color nunca es la única señal.
 */
.fitxa__estat--valid::before {
  content: '✓';
  background: var(--afa-verd-050);
  color: var(--afa-verd-600);
}

.fitxa__estat--caducat::before {
  content: '·';
  background: var(--afa-gris-100);
  color: var(--afa-gris-600);
}

/*
 * El vencido es el que importa: es la huella de una captura reenviada. Lleva
 * el mismo tinte que `.nota--avis`, que es el aviso del proyecto, y peso
 * máximo para que destaque sin depender del color.
 */
.fitxa__estat--expirat::before {
  content: '!';
  background: var(--afa-taronja-050);
  color: var(--afa-text);
}

.fitxa__estat--expirat { font-weight: var(--afa-pes-molt); }

/*
 * EL CUARTO ESTADO, y llegó con la mitad del descuento (18 de septiembre): un
 * codi anul·lat o no reconocido. El símbolo es la ✗ del validador —el mismo
 * vocabulario que usan las dos pantallas de la junta— y por eso NO reutiliza
 * la marca del vencido: «no ha funcionado nunca» y «ha caducado» son cosas
 * distintas, y aquí la primera puede querer decir que la credencial de esta
 * familia está suspendida.
 *
 * Rojo sobre su tinte, como el CADUCAT del validador: es el único de los
 * cuatro que describe algo que la familia no puede arreglar sola.
 */
.fitxa__estat--invalid::before {
  content: '✗';
  background: var(--afa-vermell-050);
  color: var(--afa-vermell-600);
}

/* La sesión en la que estás: se marca, y no lleva botón de cerrar. */
.fitxa--aquesta { border-color: var(--afa-accent); }

.fitxa__etiqueta {
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  color: var(--afa-blau-700);
  /*
   * ── DUES LÍNIES ABANS QUE SORTIR DE LA CAIXA ─────────────────────────
   *
   * Aquí hi havia `white-space: nowrap` i «Aquest dispositiu» se sortia de la
   * targeta per la dreta. Ho va trobar David amb l'app a la mà: *«sería
   * adecuado emplear dos líneas, como en "Afegir membre"»*.
   *
   * Sense `nowrap`, l'amplada mínima d'aquesta caixa passa a ser la de la
   * paraula més llarga en lloc de la de la frase sencera, i llavors sí que hi
   * cap. `flex: none` la protegeix d'encongir-se per sota d'això, que és el
   * que fa que el text de l'esquerra cedeixi primer.
   *
   * `text-align: right` perquè les dues línies acabin a la mateixa vora: sense
   * ell, la segona quedaria alineada a l'esquerra de la seva pròpia caixa i es
   * llegiria com un escaló.
   */
  flex: none;
  text-align: right;
}

/*
 * ── LA FITXA QUE ES DESPLEGA ─────────────────────────────────────────────
 *
 * Proposta de David seguint el que ja fa Gestió: es veu el NOM, i el detall
 * s'obre en pitjar. La targeta és la mateixa `.fitxa` de sempre; el que
 * canvia és que porta un `<summary>` a dins.
 *
 * El farcit se'n va de `.fitxa` a les seves parts perquè la tira d'accions
 * ha d'arribar als caires: amb el coixí a la targeta, una tira «de caire a
 * caire» hauria quedat surant amb vint píxels a banda i banda.
 */
.fitxa--plec {
  display: block;
  padding: 0;
  overflow: hidden;                      /* la tira respecta el redondeig */
}

.fitxa--plec > .fitxa__cap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--afa-espai-3);
  padding: var(--afa-espai-4);
  cursor: pointer;
  list-style: none;
}

/* Les dues maneres d'amagar el triangle nadiu: Safari té la seva. */
.fitxa--plec > summary::-webkit-details-marker { display: none; }
.fitxa--plec > summary::marker { content: ''; }

/*
 * LA FLETXA LA DIBUIXEM NOSALTRES i gira en obrir-se. Un `<summary>` sense
 * cap senyal d'estat és un botó que no diu si ja l'has premut — és la mateixa
 * regla que ja porta el plec dels filtres de Gestió.
 */
.fitxa--plec > summary::after {
  content: '';
  /*
   * VA AL CAIRE DRET I NO AL COSTAT DEL NOM, que és on la vaig posar primer:
   * penjada de `.fitxa__persona` queia sota els cognoms —perquè aquells són un
   * bloc— i es llegia com una tercera línia de dades. Com a tercer element del
   * `flex` del `<summary>`, el `space-between` la deixa on s'espera una fletxa
   * de desplegar: a la dreta del tot.
   */
  flex: none;
  width: .5em;
  height: .5em;
  border: 2px solid var(--afa-text-suau);
  border-width: 0 2px 2px 0;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .15s ease;
}
.fitxa--plec[open] > summary::after {
  transform: translateY(2px) rotate(-135deg);
}

/*
 * I LA PASTILLA DEIXA D'ENGANXAR-SE A LA FLETXA. Amb tres elements i
 * `space-between`, «Sóc jo» quedaria a mig camí; amb el marge automàtic
 * s'arrambla al grup de la dreta i el nom es queda sol a l'esquerra.
 */
.fitxa--plec > summary .fitxa__estat { margin-left: auto; }

.fitxa__persona { min-width: 0; }

/*
 * EL NOM GRAN I ELS COGNOMS A SOTA. Repartiment de David: el nom de pila és
 * el que es reconeix d'un cop d'ull i els cognoms són la precisió, així que
 * porten el cos petit i el pes normal.
 */
.fitxa__cognoms {
  display: block;
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  margin-top: 1px;
  overflow-wrap: anywhere;
}

/*
 * `__desplegat` i no `__detall`: aquell nom ja el porta la línia petita sota
 * el títol a «Els meus usos» i a «Les meves sessions». Un nom per a dues coses
 * es toca una i es trenca l'altra, i no es veu llegint el full — es veu a la
 * pantalla. Ho va parar la prova de classes duplicades.
 */
.fitxa__desplegat {
  padding: 0 var(--afa-espai-4) var(--afa-espai-4);
}

.fitxa__dada {
  margin: 0;
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  overflow-wrap: anywhere;
}

/* Qui no ha entrat mai NO rep cap avís de l'AFA: no és una dada més. */
.fitxa__dada--avis { color: var(--afa-taronja-700); font-weight: var(--afa-pes-fort); }

/*
 * ── LA TIRA D'ACCIONS ────────────────────────────────────────────────────
 *
 * Disseny de David: dos botons al peu de la targeta desplegada, al 50% d'una
 * tira que va de caire a caire. Substitueix dos enllaços solts a sota, que
 * quedaven com una nota al peu d'una cosa que no ho era.
 *
 * `1fr 1fr` i no un flex amb `flex: 1`: amb el flex, el botó del text més
 * llarg s'endú més ample i la partició deixa de ser al mig. Amb la graella,
 * les dues meitats són iguals digui el que digui el rètol.
 */
.fitxa__tira {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.tira__boto {
  /*
   * ── 44 I NO 48, i és el terra ────────────────────────────────────────
   *
   * David els volia *«un poco menos altas, no mucho»*. Els 48 són el token de
   * la casa (`--afa-tap-min`, el mínim de Material); 44 és el terra de WCAG
   * 2.5.5 i de la guia d'Apple, o sigui el número per sota del qual ja no es
   * pot baixar sense que això deixi de ser un objectiu tàctil. Aquí es fa
   * servir el terra i per això va en cru: **no és una mida triada, és un
   * límit**, i posar-lo com a token convidaria a escampar-lo.
   */
  min-height: 44px;
  padding: var(--afa-espai-2);
  border: 0;
  font-family: inherit;
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-fort);
  cursor: pointer;

  /*
   * ── PLENES, NO DE TEXT ───────────────────────────────────────────────
   *
   * Petició de David: *«invertir los colores… letra blanca y la caja con el
   * color»*. Guanya alguna cosa més que aspecte: dues meitats plenes es
   * distingeixen sense mirar-hi —una és blava i l'altra vermella— i abans
   * eren dos textos de color en una tira blanca, que és una diferència que
   * cal buscar.
   *
   * I ES PODEN ENDUR EL FILET DEL MIG: separava dues meitats que ara les
   * separa el color. Una ratlla entre dos blocs plens és una peça que no fa
   * cap feina.
   */
  background: var(--afa-primari);
  color: var(--afa-primari-text);
}

/*
 * EL PERILL ES DIU AMB EL VERB I AMB EL COLOR, mai només amb el color: el
 * botó ja diu «Treu de la família» i en pitjar-lo diu «Segur? Torna a
 * prémer». El vermell és la tercera senyal, no la primera — el dia que algú
 * no distingeixi el vermell del marí, el text segueix dient què fa.
 */
.tira__boto--perill { background: var(--afa-vermell-600); }

/*
 * EL `:hover` ENFOSQUEIX EN LLOC DE CANVIAR DE COLOR, i no és mandra: un
 * color nou per a cada estat de cada botó són dues parelles més a mesurar i
 * dos tokens que ningú ha decidit. Enfosquir un fons que ja porta text blanc
 * **només pot millorar-ne el contrast**, així que la mesura del color base
 * segueix valent per a l'estat de damunt.
 */
.tira__boto:hover { filter: brightness(.92); }

.fitxa__nom {
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-fort);
  margin: 0;
  /* Permís per partir el correu. És l'únic text del projecte sense espais i
     que pot ser arbitràriament llarg; es parteix lleig i es llegeix, que és
     infinitament millor que endur-se la pantalla. Ver `.fitxa > *`. */
  overflow-wrap: anywhere;
}

/* ── Borrar avisos ───────────────────────────────────────────────────────── */
.avis-item { position: relative; padding-right: 3rem; }

.avis-item__esborrar {
  position: absolute;
  top: var(--afa-espai-2);
  right: var(--afa-espai-2);
  width: 44px;                       /* objetivo táctil, no un aspa de 12 px */
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  border-radius: var(--afa-radi-s);
  color: var(--afa-gris-600);
  font-size: var(--afa-mida-l);
  line-height: 1;
  cursor: pointer;
}

.avis-item__esborrar:hover {
  background: var(--afa-vermell-050);
  color: var(--afa-vermell-600);
}

.avis-item__esborrar:focus-visible {
  outline: 3px solid var(--afa-accent);
  outline-offset: 1px;
}

.avisos__peu {
  padding-top: 0;
  align-items: center;
  gap: var(--afa-espai-2);
}

.avisos__retencio {
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
  text-align: center;
  margin: 0;
}

/* ── Segundo factor ───────────────────────────────────────────────────────
 *
 * Esta sección usaba CINCO variables que no existen en tokens.css
 * (--afa-esp-m, --afa-esp-s, --afa-esp-xs, --afa-muted, --afa-blau-050), y
 * una variable inexistente no da error: invalida la declaración al calcular
 * el valor. O sea que los márgenes valían cero y la caja de la clave secreta
 * se quedaba sin fondo, justo en la pantalla donde alguien tiene que copiar
 * 32 caracteres a mano. Corregidas a los tokens que sí existen.
 *
 * Y se ha retirado `.totp__recup`: era el estilo de los códigos de
 * recuperación, que David quitó del producto en cuanto los vio («nadie los
 * guarda»). Estilo de algo que ya no se pinta en ningún sitio.
 */

.totp__pas {
  margin: var(--afa-espai-4) 0 var(--afa-espai-2);
  font-size: var(--afa-mida-s);
  line-height: 1.5;
}

.totp__qr {
  display: flex;
  justify-content: center;
  /* Fondo blanco propio: el QR necesita contraste absoluto y el resto de la
     pantalla no tiene por qué serlo. */
  background: var(--afa-blanc);
  padding: var(--afa-espai-4);
  border-radius: var(--afa-radi-m);
}

.totp__manual {
  margin: var(--afa-espai-4) 0 var(--afa-espai-1);
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
}

/* La clave en monoespaciada y partible: son 32 caracteres que alguien puede
   tener que copiar a mano en un teclado de móvil. */
.totp__clau code {
  display: block;
  font-family: var(--afa-font-mono);
  font-size: var(--afa-mida-s);
  letter-spacing: .08em;
  word-break: break-all;
  background: var(--afa-gris-100);
  color: var(--afa-blau-900);
  padding: var(--afa-espai-2);
  border-radius: var(--afa-radi-s);
}


/*
 * LA REGLA VIEJA DE LA VERSIÓN SE HA IDO. Posicionaba el número DENTRO del
 * ángulo azul de la tarjeta, que es donde vivía hasta el diseño 2A. Al
 * sacarlo fuera del `<article>` ese `position: absolute` dejó de tener un
 * ancestro posicionado y el número se iba al fondo de la página, **detrás de
 * la barra inferior**: estaba en el HTML y no se veía en ninguna pantalla.
 * La regla buena está arriba, junto al resto de la credencial.
 */


/*
 * Cuando lo que corre NO es lo que el servidor ha publicado.
 *
 * Es justo el estado que esto viene a resolver: la caché del aparato se ha
 * quedado atrás y hay que cerrar la app y volver a abrirla. Se marca con el
 * color de aviso de la casa y con un símbolo, nunca solo con el color.
 */
.credencial__versio[data-endarrerida="1"] {
  /*
   * Y aquí sí sube el brillo, que es lo que hace que el aviso se vea sin
   * gritar: el estado normal es gris desde que se pidió que fuera un matiz,
   * así que el naranja pálido destaca por diferencia en vez de por tamaño. El
   * símbolo sigue estando, porque el color nunca es la única señal.
   */
  color: var(--afa-taronja-050);
  -webkit-text-stroke: 0.5px var(--afa-blau-900);
}

/*
 * EL SÍMBOLO: UN CÍRCULO DE RECARGA, NO UNA ADMIRACIÓN.
 *
 * Era un `!` y lo cambió David el 14 de septiembre. El motivo es bueno y va
 * más allá del dibujo: desde que la etiqueta se repinta sola al tomar el
 * control el worker nuevo, este estado dura **un segundo**, no hasta que
 * alguien cierre la app. Una admiración para algo que se está arreglando
 * mientras lo miras es una alarma que no toca; un círculo de recarga dice lo
 * que de verdad pasa y se apaga cuando termina.
 *
 * Va aquí y no en `app.js` porque es donde están los demás símbolos del
 * proyecto (las marcas ✓ ✗ ! de las notas y del validador), y porque así el
 * JavaScript no escribe ni un carácter visible dentro de la tarjeta.
 *
 * U+21BB CLOCKWISE OPEN CIRCLE ARROW. **No es un emoji** —no está en la lista
 * de Unicode— así que no hace falta el selector de presentación de texto que
 * sí necesitarían ↩ o ⤴.
 *
 * LO QUE SE ACEPTA A CAMBIO, y es decisión suya: la etiqueta va en la
 * monoespaciada del sistema, y no todas la traen. Donde falte, el navegador
 * salta a otra fuente **solo para ese carácter** y puede quedar con otro peso
 * o desalineado del número. No es tofu ni deja de verse; es que en algún
 * aparato no quedará tan fino. La alternativa era dibujarlo en SVG, y no
 * compensaba el trabajo para nueve de cada diez casos.
 */
.credencial__versio[data-endarrerida="1"]::after {
  content: ' ↻';
}


/*
 * ── LA CHAPA DE IDENTIDAD Y LA BARRA INFERIOR (diseño 2A) ────────────────
 *
 * Sustituyen a la campana y a la hamburguesa. Los valores son los del handoff.
 */
.capcalera__avatar {
  width: 1.875rem;                       /* 30px */
  height: 1.875rem;
  border-radius: 0.625rem;               /* 10px — cuadrado redondeado, no círculo */
  background: var(--afa-blau-700);
  color: var(--afa-blanc);
  display: grid;
  place-items: center;
  font-size: 0.6875rem;                  /* 11px */
  font-weight: var(--afa-pes-molt);
  letter-spacing: .02em;
  flex: none;
}

.barra {
  /*
   * AQUÍ SOLO LA PIEL. La posición, la columna y el suelo son de
   * `.pantalla__barra`, en shared/css/tokens.css — son lo mismo que la barra
   * de la zona de gestión y estaban escritos dos veces.
   */
  background: var(--afa-blanc);
  border-top: 1px solid var(--afa-calid-100);
  padding-inline: 8px;              /* el vertical lo pone `.pantalla__barra` */
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 2px;
}

.barra__pestanya {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  color: var(--afa-calid-600);           /* desviación medida: 4,86:1 */
  font-size: 0.594rem;                   /* 9,5px */
  line-height: 1.2;
}

/*
 * Només MIDA. El farciment i el traç viatgen amb el dibuix, als atributs del
 * SVG que escriu `Disseny::icona()`: si els repetíem aquí, la barra tindria una
 * versió del joc i el full una altra, que és el que fins avui feia que la
 * campana es veiés de tres maneres.
 */
.barra__icona {
  width: 1.25rem;                        /* 20px */
  height: 1.25rem;
}

/*
 * DÓNDE ESTÁS: color Y peso, nunca solo color. Es el criterio 1.4.1 de WCAG y
 * la misma decisión que el triángulo del menú lateral de gestión.
 */
.barra__pestanya[aria-current="page"] {
  color: var(--afa-blau-700);            /* 12,02:1 */
  font-weight: var(--afa-pes-molt);
}

/*
 * ── LA PESTANYA DE GESTIÓ, EN CÀPSULA (disseny 3A) ───────────────────────
 *
 * «Gestió n'ocupa el lloc [d'Usos], amb la vora taronja com a senyal que és
 * una altra zona. Un toc per entrar-hi.»
 *
 * Els marges negatius són del disseny i fan la feina: la càpsula sobresurt del
 * farciment de la barra per amunt i per avall, així que sembla enganxada a la
 * fila en comptes de flotar-hi dins. Sense ells, la barra creixeria 11 px.
 *
 * LA TINTA ÉS `taronja-700` I NO EL `#B86400` DEL DISSENY, mesurat: el seu
 * dona **3,94:1** sobre la càpsula i aquí el text fa 9,5 px, o sigui que AA
 * demana 4,5. `--afa-taronja-700` en fa 4,64 i és un color de la SEVA paleta
 * —el mateix canvi que ja es va fer a les píndoles del Compte—.
 *
 * I el color no és l'únic senyal, que és la regla de sempre: hi ha la càpsula,
 * la vora, el pes de la lletra i una icona diferent de les altres quatre.
 */
.barra__pestanya--gestio {
  background: var(--afa-taronja-050);
  border: 1px solid var(--afa-taronja-200);
  border-radius: 13px;
  padding: 5px 0 6px;
  margin: -5px 0 -6px;
  color: var(--afa-taronja-700);         /* 4,64:1 sobre la càpsula */
  font-weight: var(--afa-pes-molt);
}


/*
 * El punto de aviso. NO lleva número a propósito: a 8px un «9+» no se lee, y
 * lo que la pestaña tiene que decir es «hay algo», no cuánto. El recuento
 * exacto está dentro, en la lista.
 *
 * El borde blanco lo despega del icono cuando se solapan.
 */
.barra__punt {
  position: absolute;
  top: -2px;
  right: 22%;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--afa-taronja-500);
  border: 1.5px solid var(--afa-blanc);
}

/*
 * ── LA COLUMNA QUE SOSTIENE LA BARRA ──────────────────────────────────────
 *
 * Aquí había `padding-bottom: 5.25rem` para que la última fila de una
 * pantalla larga no quedara debajo de la barra fija. Con la barra en el flujo
 * ese hueco sobra —ocupa su sitio ella sola— y además estorbaría: serían 84
 * píxeles de crema muerta bajo la navegación.
 *
 * Lo que hace falta ahora es que el cuerpo mida siempre lo que la pantalla,
 * para que en una vista corta —la del carnet, sin scroll— el contenido empuje
 * la barra hasta abajo en vez de dejarla flotando bajo la tarjeta. Es la
 * maqueta de Kronos: cabecera, cuerpo que crece, barra.
 *
 * Y EL RELLENO INFERIOR DEL CUERPO PASA A CERO. El `env(safe-area-inset-bottom)`
 * del atajo de arriba metería el indicador de inicio POR DEBAJO de la barra, o
 * sea 34 px de crema entre la barra y el borde: exactamente el hueco que
 * estamos quitando. Ese margen ya lo pone la barra en su propio relleno, que
 * es donde toca —ahí el color es el de la barra—.
 */
@media (min-width: 64rem) {
  /* En escritorio no hay pulgar: la navegación vuelve al lateral de siempre. */
  .barra { display: none; }
}

/*
 * ── EL FULL DEL COMPTE, EN PÍLDORAS (diseño 3B) ──────────────────────────
 *
 * Portado del código fuente del handoff. Va TODO en la hoja y ni una línea en
 * el PHP: el marcado que ya emitía `Disseny::menuOpcions()` —icono, etiqueta,
 * encabezado de grupo y chip de rol— resultó ser exactamente la estructura que
 * el diseño necesitaba. Reescribirlo habría sido tocar el generador que
 * alimenta también la barra lateral del escritorio, y ahí no hay píldoras.
 *
 * DOS COLORES DE DESIGN NO LLEGAN A AA Y SE SUSTITUYEN POR OTROS SUYOS:
 *   blanco sobre #E07B00 a 13px ... 3,00:1  →  fondo #B8490A (crema encima 4,96)
 *   #B86400 sobre blanco a 10px ... 4,32:1  →  #A85A00 (5,09)
 * No se inventa nada: los dos sustitutos son colores que el propio diseño usa
 * en otras piezas.
 */


/* ── La píldora ─────────────────────────────────────────────────────────── */
/*
 * La PELL d'aquesta píndola —fons, vora, radi, ombra, tinta i pes— viu a
 * `tokens.css`, compartida amb la del full de Gestió. Aquí només hi queda el
 * que és d'aquesta: la fila amb icona i xifra, i el seu cos de lletra.
 */
.menu__opcio {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  min-height: var(--afa-tap-min);
  padding: 10px 15px;
  /* `<button>` no hereta la família tipogràfica: sense això, «Tanca la
     sessió» surt amb la del sistema i les altres amb la nostra. */
  font-family: inherit;
  font-size: 0.8125rem;                  /* 13px */
  cursor: pointer;
}

/*
 * El ressaltat només on hi ha punter de veritat. En una pantalla tàctil el
 * `:hover` s'ENGANXA després de tocar, i aquí es menjaria el blanc de la
 * píndola just a la fila que acabes de prémer. És el mateix que va fer
 * «desaparèixer» el codi de descompte en copiar-lo.
 */
@media (hover: hover) {
  .menu__opcio:hover { background: var(--afa-gris-100); }
}

.menu__opcio .icona-nav {
  width: 1.125rem;                       /* 18px */
  height: 1.125rem;
  flex: none;
  color: var(--afa-blau-700);
}

.menu__opcio > span { flex: 1; min-width: 0; }

/*
 * ── LA XIFRA DE CADA FILA (disseny 3B) ───────────────────────────────────
 *
 * `20,00 €`, `3`, `2`, «1 nou». És una PISTA, no un dato: la fila diu on porta
 * i el número ajuda a decidir si val la pena entrar-hi.
 *
 * `:empty` LA FA DESAPARÈIXER, i és el que permet que el servidor pinti la
 * ranura buida i JavaScript l'ompli després amb el que l'app ja ha demanat. Si
 * no s'omple mai —l'ERP no contesta, la família no té cap ús— no queda un buit
 * ni una píndola blanca surant: no hi ha res. Amb `hidden` caldria que qui
 * escriu la xifra sabés també amagar-la, i seria una cosa més per oblidar.
 *
 * El `> ` del selector no és estètic: `.menu__opcio > span` posa `flex: 1` a
 * tots els fills, i sense pujar-li l'especificitat la xifra s'estiraria i
 * empenyeria l'etiqueta.
 */
.menu__opcio > .menu__xifra {
  flex: none;
  color: var(--afa-gris-500);            /* 5,02:1 sobre blanc */
  font-size: 0.71875rem;                 /* 11,5px */
  font-weight: var(--afa-pes-fort);
  font-variant-numeric: tabular-nums;
}

.menu__xifra:empty { display: none; }

/*
 * ── AQUÍ HI HAVIA LA FILA D'«AVISOS» DESTACADA I LA DE «GESTIÓ» EN MARÍ ──
 *
 * Eren del disseny 2A, on el full repetia els destins de la barra i la fila
 * d'avisos es veia abans de llegir res. El full va deixar de repetir la barra
 * —`Disseny::barra()` diu què se'n du la barra i el full ensenya la resta—,
 * així que `avisos` i `panell` no hi poden sortir mai: **dues desenes de
 * línies que no pintaven res.**
 *
 * El senyal no es perd: la pestanya d'«Avisos» de la barra porta el punt
 * taronja quan n'hi ha de nous, i la de «Gestió» va dins de la seva càpsula.
 * És el mateix que deia 2A, dit al lloc on ara viuen les dues coses.
 */

/* Salir: el rojo del proyecto, y solo en el borde y la tinta. */
.menu__opcio--sortir {
  color: var(--afa-vermell-600);
  border-color: var(--afa-vermell-200);
  font-weight: var(--afa-pes-molt);
}
.menu__opcio--sortir .icona-nav { color: var(--afa-vermell-600); }

@media (min-width: 64rem) {
  /* En escritorio el menú vuelve a ser una lista: las píldoras son para el pulgar. */
  .menu__opcio {
    border: 0;
    border-radius: var(--afa-radi-s);
    box-shadow: none;
    padding: var(--afa-espai-2) var(--afa-espai-3);
  }
}


/*
 * ── CORRECCIONES CONTRA EL DISEÑO (15 de septiembre) ─────────────────────
 *
 * Salieron de comparar una captura del iPhone con la del handoff, una al lado
 * de la otra. Las tres son de bulto y ninguna se ve leyendo el CSS.
 */

/*
 * (1 · «todo a la izquierda» ya no vive aquí: era un segundo `.carnet` que
 * corregía el `text-align: center` de la tarjeta vieja, y ahora la corrección
 * está en la única declaración de `.carnet`, mil líneas más arriba.)
 */
/*
 * 2 · EL TÍTULO DE LA PANTALLA, que no estaba. En el diseño hay un «El meu
 * carnet» encima de la tarjeta, y no es decoración: sin él la tarjeta empieza
 * pegada a la cabecera y la pantalla no dice qué estás mirando.
 */
.carnet__titol {
  margin: 0 0 var(--afa-espai-3);
  color: var(--afa-blau-900);
  font-size: 1.1875rem;                  /* 19px */
  font-weight: var(--afa-pes-molt);
  letter-spacing: -.022em;
}

/*
 * 3 · LA PASTILLA DEL VEREDICTO, SIN TIC. Fuera de la tarjeta el símbolo sigue
 * haciendo falta —el color nunca es la única señal— pero aquí la pastilla ya
 * va acompañada de la palabra VÀLID o CADUCAT, que es texto y no color. El tic
 * dentro de una píldora de 9,5px se comía la mitad del ancho.
 */
.credencial .carnet__estat--valid::before,
.credencial .carnet__estat--caducat::before,
.credencial .carnet__estat--sense::before { content: none; }


/*
 * EL FONS DE L APP, amb la crema del disseny. La nostra #FBF8F3 és mig punt
 * més freda i, al costat de la capçalera i de la targeta, es notava.
 */
body { background: var(--afa-crema-calida); }


/*
 * VALIDESA, A LA DERECHA. Petición de David mirando la tarjeta: la fecha
 * cuelga del borde derecho de la credencial y la columna de la izquierda se
 * alinea con el antetítulo y el nombre. Las dos columnas dejan de flotar en
 * medio y la caja se cierra por sus dos lados.
 */
.credencial__graella > .credencial__camp:last-child { text-align: right; }

/*
 * ── EL SUELO DE LA BARRA: EL PARCHE SE HA RETIRADO ───────────────────────
 *
 * Aquí había un pseudoelemento que prolongaba el fondo de la barra medio
 * viewport hacia abajo para tapar el hueco que quedaba en el iPhone. Estaba
 * declarado como lo que era —«no arregla la causa: hace que deje de
 * importar»— y la causa ya está encontrada: era
 * `apple-mobile-web-app-status-bar-style: black-translucent` en la shell. El
 * porqué está escrito ahí, en `public/carnet/index.php`.
 *
 * Se retira en el mismo despliegue que el arreglo A PROPÓSITO: dejándolo, el
 * hueco quedaría tapado pasara lo que pasara y no habría forma de saber si el
 * arreglo ha servido. Si el hueco vuelve a verse, el diagnóstico estaba mal y
 * el parche está a un `git revert` de distancia.
 */

/*
 * ── EL ZOOM, BLOQUEADO (petición de David) ───────────────────────────────
 *
 * `touch-action: manipulation` quita el zoom por DOBLE TOQUE, que es el que
 * salta sin querer al tocar dos veces seguidas una pestaña o un botón y deja
 * la interfaz torcida. El pellizco lo bloquea la meta del viewport.
 */
body { touch-action: manipulation; }

/* ── Afegir el segon adult: el codi presencial ──────────────────────────
 *
 * Un QR i, a sota, el mateix codi en text. Les dues vies porten al mateix
 * lloc; el QR és comoditat i el codi tecleat és la implementació completa.
 */
.segon {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--afa-espai-3);
  /*
   * AMB TOPE I CENTRADA. Sense el `max-width` la caixa és un bloc i s'estira
   * fins als caires del contingut, o sigui gairebé tota l'amplada del mòbil,
   * amb un QR de 210 px al mig i la resta blanc. Ho va veure David.
   *
   * 16rem, i el número surt de mesurar el que hi ha a dins i no de l'ull: el
   * QR fa 204 px, el codi 224 —és ell el més ample, no el QR— i el coixí 17 a
   * cada banda, o sigui que el contingut demana 260. 16rem són 272 amb l'arrel
   * a 17 px: just, amb una mica d'aire i sense que res hagi de partir-se.
   *
   * No es fa servir `fit-content`, que s'ajustaria sol, perquè llavors qui
   * decidiria l'amplada seria el text més llarg que hi hagi a dins: el dia que
   * algú n'hi posi un de llarg, la caixa tornaria a estirar-se i ningú
   * relacionaria les dues coses. És el mateix tope i el mateix centrat que ja
   * fa servir `.login`.
   */
  max-width: 16rem;
  margin: var(--afa-espai-4) auto;
  padding: var(--afa-espai-4);
  background: var(--afa-blanc);
  border: 1px solid var(--afa-calid-100);
  border-radius: var(--afa-radi-l);
}

/* El fons blanc és del QR i no de la caixa: un codi sobre crema el llegeixen
   pitjor les càmeres barates, i n'hi ha moltes. */
/*
 * L'amplada exacta la fixa `pintarQrEn()` en píxels perquè cada mòdul caigui
 * damunt d'un nombre enter de píxels físics; l'alçada la treu el navegador de
 * la proporció del propi canvas (mesurat: amb dpr 3, atribut 629 i renderitzat
 * 210x210). Aquí només s'impedeix que desbordi si aquell càlcul no ha arribat
 * a executar-se, que és el mateix que fa `.carnet__qr canvas`.
 */
.segon__qr {
  display: block;
  max-width: 100%;
  height: auto;
  background: var(--afa-blanc);
  border-radius: var(--afa-radi-s);
  image-rendering: pixelated;
}

/*
 * El codi, gros i monoespaiat. Va partit en dos grups de quatre —ho fa el
 * JavaScript— perquè un bloc de vuit caràcters es dicta malament, i amb
 * `tabular-nums` els grups no ballen d'amplada mentre el codi rota.
 */
.segon__codi {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--afa-mida-xl);
  font-weight: var(--afa-pes-molt);
  letter-spacing: .18em;
  color: var(--afa-blau-900);            /* 14,84:1 */
  font-variant-numeric: tabular-nums;
}

.segon__renova,
.segon__carregant {
  margin: 0;
  font-size: var(--afa-mida-xs);
  color: var(--afa-text-suau);
  text-align: center;
}



/* ══════════════════════════════════════════════════════════════════════════
 * DESCOMPTES — el mosaic de comerços i la fitxa flotant
 *
 * Encàrrec de David: *«mosaicos de dos columnas y múltiples filas, en las que
 * representaríamos "cuadrados" (similar a lo que vemos al entrar en "gestió"),
 * y ubicando allí los logos de los comercios, presentando un cuadro flotante
 * indicando los descuentos aportados»*.
 *
 * Els «quadrats» als quals es refereix són les caixes de `/gestio`
 * (`.g__xifra` a `gestio.css`): blanc, vora d'1px i radi mitjà. Aquí la pell
 * és la mateixa que ja porten `.fitxa`, `.bloc` i `.g__xifra`, perquè una
 * quarta manera de dibuixar una caixa faria que la pantalla semblés d'una
 * altra app. El que canvia és la FORMA: aquestes són quadrades de debò.
 *
 * ── PER QUÈ EL QUADRAT ES MANTÉ QUADRAT ──────────────────────────────────
 *
 * `aspect-ratio: 1` sol NO garanteix res: si el contingut és més alt, la
 * caixa creix i la graella queda irregular. El que ho fixa és
 * `overflow: hidden` al costat — amb un desbordament diferent de `visible`,
 * la mida mínima automàtica de l'eix dependent de la ràtio deixa de ser la
 * del contingut. Les dues línies van juntes i cap de les dues sobra.
 *
 * I perquè el retall no arribi a passar mai, el nom es limita a DUES línies
 * i el descompte a UNA: es talla el text amb punts suspensius, que es llegeix,
 * en comptes de tallar-lo per la meitat amb la tisora del `overflow`.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ── La capçalera de la pantalla ────────────────────────────────────────── */
/*
 * Mateixa columna de 34rem que `.pagina`, `.llista` i `.avisos`: el títol
 * s'ha d'alinear amb el que hi ha a sota. Una capçalera més ampla que el seu
 * contingut ja va costar una pantalla que semblava dues mal enganxades.
 */
.desc__cap {
  max-width: 34rem;
  margin: var(--afa-espai-5) auto 0;
  padding: 0 var(--afa-espai-4);
}

.desc__titol {
  font-size: var(--afa-mida-l);
  font-weight: var(--afa-pes-molt);
  line-height: 1.2;
  margin: 0;
}

/* 7,58:1 sobre el fons de l'app. */
.desc__intro {
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
  line-height: 1.5;
  margin: var(--afa-espai-2) 0 0;
}

/* ── El mosaic ──────────────────────────────────────────────────────────── */
/*
 * `minmax(0, 1fr)` i no `1fr`: una pista de graella té mida mínima `auto`,
 * o sigui el contingut, i un nom de comerç llarg eixamplaria la columna i
 * se'n portaria la pantalla cap a la dreta. És el mateix `min-width: 0` que
 * ja va caldre a `.fitxa` amb un correu llarg, dit en llenguatge de graella.
 */
.desc__mosaic {
  list-style: none;
  max-width: 34rem;
  margin: var(--afa-espai-4) auto 0;
  padding: 0 var(--afa-espai-4) var(--afa-espai-7);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--afa-espai-3);
}

.desc__rajola { min-width: 0; }

/*
 * LA RAJOLA SENCERA ÉS EL BOTÓ. El projecte demana 44px de terra tocable i
 * aquí en fa 138 de costat en un telèfon de 320 — el dit no ha d'encertar
 * res. Per això el `<button>` ocupa tot el `<li>` i no hi ha cap enllaç a
 * dins: dos objectius dins d'un objectiu és com es fa una diana que falla.
 */
.desc__obrir {
  width: 100%;
  aspect-ratio: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  /*
   * SENSE COIXÍ I SENSE SEPARACIÓ, des que hi ha cinta: la cinta ha d'arribar
   * als tres caires de dalt i qualsevol coixí aquí la desenganxaria. El coixí
   * el posa `.desc__cos`, que és el que sí que ha de respirar.
   *
   * I `stretch` en comptes de `center`: els dos fills —cinta i cos— han
   * d'ocupar tota l'amplada. Amb `center` la cinta amidaria el seu contingut i
   * quedaria una barra curta al mig de la targeta.
   */
  justify-content: flex-start;
  gap: 0;
  padding: 0;
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
  box-shadow: var(--afa-ombra-1);
  color: var(--afa-text);
  font-family: inherit;
  text-align: center;
  cursor: pointer;
}

/*
 * EL REALÇ NO TOCA CAP FONS, I ÉS A PROPÒSIT. Canviar el fons de la rajola
 * obligaria a tornar a mesurar les tres parelles de text que hi ha a dins
 * —el nom, el descompte i el monograma— i el monograma, que ja és un tint,
 * desapareixeria damunt d'un tint. El que canvia és la VORA i l'ombra: una
 * senyal de forma i de relleu, no de color, i el contrast de dins no es mou.
 *
 * `@media (hover: hover)` perquè en una pantalla tàctil el `:hover` s'enganxa
 * després de tocar i la rajola es queda realçada sense motiu.
 */
@media (hover: hover) {
  .desc__obrir:hover {
    border-color: var(--afa-accent);
    box-shadow: var(--afa-ombra-2);
  }
}

.desc__obrir:focus-visible {
  outline: 3px solid var(--afa-accent);
  outline-offset: 2px;
}

/*
 * EL FORAT DE LA MARCA, I EL COMPTE QUE HI CAP.
 *
 * Mesurat al telèfon més petit que es contempla, 320px: el mosaic deixa
 * columnes de 138 i la rajola, amb els seus 12 de coixí, en té 114 de
 * contingut. Amb el 38% d'abans en sortien 43,3, i la columna sumava
 * 43,3 + 8 + 34 (dues línies de nom) + 4 + 18 (el descompte) = 107 de 114.
 * A 375 en sobraven 24 i a tres columnes, 22.
 *
 * ── UN 20 % MÉS GRAN, I A 320 NO HI CAP SENCER ───────────────────────────
 *
 * Petició de David el 29 de setembre de 2026. El 38% passa a 45,6%, i
 * l'aritmètica de dalt és justament la que diu on és el límit: a 320 en
 * surten 52,0 i la columna sumaria **116 de 114**, o sigui dos píxels de més.
 *
 * NO ES REBAIXA PER AIXÒ, i el motiu és el `flex: 0 1 auto` de sota: qui
 * cedeix és el DIBUIX i no el text, així que en aquell telèfon el forat es
 * queda en uns 50 i el logotip creix un 16% en comptes d'un 20. De 375 en
 * amunt —que és tot el que la família fa servir de debò— el 20% hi cap
 * sencer. L'alternativa era encongir el nom del comerç, i un nom tallat és
 * pitjor que un logotip quatre píxels més petit.
 *
 * `min-height: 0` és el que ho fa possible, i val també per si algú amplia la
 * lletra del sistema. El logotip segueix sense retallar-se perquè
 * `object-fit: contain` no depèn que el forat sigui quadrat.
 */
.desc__marca {
  flex: 0 1 auto;
  min-height: 0;
  width: clamp(2.7rem, 45.6%, 4.8rem);
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

/*
 * EL LOGOTIP ES CONTÉ, MAI ES RETALLA. El logotip d'un comerç no és nostre
 * per tallar-li un tros: `contain` el deixa sencer dins del forat quadrat i
 * el que sobra és aire. `object-fit: cover` ompliria millor i és exactament
 * el que no es pot fer.
 */
.desc__logo {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/*
 * EL MONOGRAMA, QUAN NO HI HA LOGOTIP.
 *
 * Un sol parell de colors de la paleta per a tots els comerços, i no un color
 * per categoria ni res derivat d'un hash: un color triat per una funció no el
 * pot mesurar ningú, i en aquest projecte una parella que no és a
 * `bin/contrast.php` és una parella que no s'ha mirat.
 *
 * Tint de la casa amb tinta marina: **10,59:1**, molt per damunt del 4,5 que
 * demana AA. És el mateix tint de la càpsula de «Gestió» i de les seccions
 * actives, o sigui que no estrena cap manera nova de dir res.
 *
 * I va DISCRET a propòsit: el monograma substitueix un logotip, no competeix
 * amb els que sí que n'hi ha. Un quadrat marí massís cridaria més que les
 * marques de veritat, que és just al revés del que ha de passar.
 */
.desc__inicials {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--afa-taronja-050);
  border: 1px solid var(--afa-taronja-200);
  border-radius: var(--afa-radi-s);
  color: var(--afa-blau-700);
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-molt);
  letter-spacing: .04em;
}

/*
 * Dues línies i prou. `overflow-wrap: anywhere` perquè un nom d'una sola
 * paraula llarga no eixampli la columna — la mateixa lliçó del correu que
 * se'n portava «La meva família».
 */
.desc__nom {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  max-width: 100%;
  margin-top: var(--afa-espai-1);
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  line-height: 1.3;
  color: var(--afa-text);
  overflow-wrap: anywhere;
}

/*
 * El descompte a la rajola: 5,09:1 sobre blanc. El color no és l'única
 * senyal —va en el pes màxim i a la línia de sota del nom, que és on l'ull
 * el busca— perquè qui no distingeix el taronja l'ha de poder llegir igual.
 */
.desc__valor {
  display: block;
  max-width: 100%;
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-molt);
  line-height: 1.2;
  color: var(--afa-taronja-700);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Cap comerç encara. Mateixa pinta que el buit dels avisos. */
.desc__buit {
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--afa-espai-7) var(--afa-espai-4);
  text-align: center;
  font-size: var(--afa-mida-s);
  line-height: 1.6;
  color: var(--afa-text-suau);
}

/* ── 48rem: tres columnes ───────────────────────────────────────────────── */
/*
 * La columna es queda en 34rem, com la resta de l'app: el que canvia és
 * quantes rajoles hi caben, no com d'ampla és la pantalla. Amb tres, cada
 * quadrat fa uns 170px, que és més que els 138 del telèfon.
 */
@media (min-width: 48rem) {
  .desc__mosaic { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/*
 * ── 64rem: ni centrat ni encoixinat ──────────────────────────────────────
 *
 * Exactament el que fan `.avisos` i `.llista` unes línies més amunt, i pel
 * mateix motiu: amb la barra lateral la columna de contingut amida 900px i
 * el `margin: 0 auto` deixava el títol a l'esquerra del tot i la llista 200px
 * més endins. Es conserva la MIDA de 34rem, que és el que alinea el títol
 * amb el que té a sota; el que se'n va és el centrat.
 */
@media (min-width: 64rem) {
  .desc__cap,
  .desc__mosaic {
    margin-inline: 0;
    padding-inline: 0;
  }
}

/* ── La fitxa flotant ───────────────────────────────────────────────────── */
/*
 * El vel i la caixa els posa la declaració compartida amb `.capa`, a dalt
 * d'aquest fitxer. Aquí només hi ha el que és d'aquesta fitxa.
 *
 * `position: relative` perquè la creu de tancar hi pugui seure a la
 * cantonada; la declaració compartida no en porta perquè la guia
 * d'instal·lació no la necessita.
 */
.desc__full-caixa {
  position: relative;
  text-align: center;
}

/*
 * 44px clavats d'objectiu tàctil, com el botó d'esborrar un avís — no una
 * creu de 12px. Va damunt del cantó i el títol li reserva el lloc més avall.
 */
.desc__full-tanca {
  position: absolute;
  top: var(--afa-espai-2);
  right: var(--afa-espai-2);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--afa-radi-s);
  background: none;
  color: var(--afa-gris-600);
  font-family: inherit;
  font-size: var(--afa-mida-l);
  line-height: 1;
  cursor: pointer;
}

.desc__full-tanca:focus-visible {
  outline: 3px solid var(--afa-accent);
  outline-offset: 1px;
}

/* El mateix forat quadrat de la rajola, més gran: el logotip segueix sense
   retallar-se i el monograma segueix sent el mateix tint. */
.desc__full-marca {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  aspect-ratio: 1;
  margin: 0 auto var(--afa-espai-3);
}

/*
 * EL LLOC DE LA CREU, RESERVAT. El títol està centrat i la creu és a la
 * cantonada: sense la reserva, un nom llarg passaria per sota de la creu en
 * un telèfon de 320. És la mateixa correcció que la capçalera de «La meva
 * família» va necessitar amb el botó d'afegir membre — el text ha de saber
 * que la cantonada està ocupada.
 */
.desc__full-nom {
  margin: 0 0 var(--afa-espai-3);
  padding: 0 2.25rem;
  font-size: var(--afa-mida-l);
  font-weight: var(--afa-pes-molt);
  line-height: 1.25;
  color: var(--afa-text);
  overflow-wrap: anywhere;
}

/*
 * EL DESCOMPTE ÉS EL MÉS GRAN DE LA CAIXA, que és el que David va demanar.
 *
 * Va en píndola i no només en lletra grossa: el tint li dona cos i el
 * distingeix del nom sense dependre de la mida, que aquí no és fixa.
 * Tinta 4,64:1 sobre el tint — passa AA per a text normal, o sigui amb marge
 * de sobra per a una xifra d'entre 22 i 40px.
 *
 * ── PER QUÈ LA MIDA ÉS FLUIDA I NO `--afa-mida-xxl` A SEQUES ─────────────
 *
 * `comercos.descompte` és un VARCHAR(80): tant hi pot dir «10 %» com «2x1 en
 * llibres de text». A 40px clavats, la segona ocuparia quatre línies en un
 * telèfon de 320. El `clamp()` la deixa en 22px allà i la puja fins als 40 a
 * partir de 500px d'ample, i `overflow-wrap: anywhere` garanteix que no
 * desbordi mai encara que sigui una sola paraula llarga.
 *
 * `inline-block` i no `block`: una píndola de caire a caire seria una caixa
 * que ocupa tot l'ample perquè sí, i en aquest projecte això té nom.
 */
.desc__full-valor {
  display: inline-block;
  max-width: 100%;
  margin: 0 0 var(--afa-espai-4);
  padding: var(--afa-espai-2) var(--afa-espai-4);
  background: var(--afa-taronja-050);
  border: 1px solid var(--afa-taronja-200);
  border-radius: var(--afa-radi-m);
  color: var(--afa-taronja-700);
  /*
   * ── ERA PER A UN NÚMERO, I QUASI CAP DESCOMPTE ÉS UN NÚMERO ───────────
   *
   * `clamp(l, 8vw, xxl)` donava **30px a 375** i 34 a un telèfon gran. Per a
   * «20 %» és exactament el que toca: el descompte és el que la família ve a
   * mirar. Però el camp fa 80 caràcters i el que hi escriu la junta són
   * frases —«20 € de descompte en cada sessió», «10 % en les mensualitats»—,
   * i amb `overflow-wrap: anywhere` allò es convertia en tres o quatre línies
   * enormes que es menjaven la fitxa.
   *
   * David, el 29 de setembre de 2026: «se ven ENORMES. Eso posibilitaría
   * insertar algunos caracteres más».
   *
   * 5,5vw són 20,6px a 375 i 17,6 a 320: un terç menys, i hi caben prop del
   * doble de caràcters per línia. Segueix sent la peça més gran de la fitxa
   * —el nom en fa 22— que és el que ha de ser.
   */
  font-size: clamp(var(--afa-mida-m), 5.5vw, var(--afa-mida-l));
  font-weight: var(--afa-pes-molt);
  line-height: 1.15;
  overflow-wrap: anywhere;
  /*
   * `pre-line` i no `pre`: es respecten els salts que la junta escriu i es
   * col·lapsen els espais de més. Sense això, el camp deixa escriure dues
   * línies, les desa, i la fitxa n'ensenya una — una dada que menteix, i la
   * pitjor mena, perquè qui l'escriu no ho sap.
   */
  white-space: pre-line;
}

/*
 * Les condicions i les dades tornen a l'esquerra: el cap de la fitxa és un
 * cartell i això és una llista. La separació la marca una línia de dalt, que
 * és el que ja fa el projecte per separar sense inventar-se una capsa nova.
 */
.desc__full-condicions {
  margin: 0;
  padding-top: var(--afa-espai-4);
  border-top: 1px solid var(--afa-calid-100);
  text-align: left;
  font-size: var(--afa-mida-s);
  line-height: 1.5;
  color: var(--afa-text-suau);
}

/*
 * Etiqueta i valor en dues columnes. `minmax(0, 1fr)` a la segona i
 * `overflow-wrap: anywhere` al valor: una adreça llarga o un web sense cap
 * espai no poden eixamplar la caixa.
 */
.desc__full-dades {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--afa-espai-3);
  row-gap: var(--afa-espai-2);
  margin: var(--afa-espai-4) 0 0;
  padding-top: var(--afa-espai-4);
  border-top: 1px solid var(--afa-calid-100);
  text-align: left;
  font-size: var(--afa-mida-s);
}

.desc__full-dades dt {
  color: var(--afa-text-suau);
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
}

.desc__full-dades dd {
  margin: 0;
  min-width: 0;
  color: var(--afa-text);
  overflow-wrap: anywhere;
}

/* El subratllat es queda: un enllaç no es pot distingir només pel color. */
.desc__full-dades a {
  color: var(--afa-primari);
  text-decoration: underline;
}

.desc__full-dades a:focus-visible {
  outline: 3px solid var(--afa-accent);
  outline-offset: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * DESCOMPTES · ORDENAR PER PROXIMITAT
 * ═══════════════════════════════════════════════════════════════════════════ */





/* ═══════════════════════════════════════════════════════════════════════════
 * DESCOMPTES · LA CINTA DE LA RAJOLA
 *
 * Idea de David, presa de la targeta del panell de gestió: el ganxo a
 * l'esquerra sobre color i el temps a la dreta sobre el clar.
 *
 * ── PER QUÈ 24px I NO L'ALÇADA DE LA DEL PANELL ──────────────────────────
 *
 * Allà la cinta corona una caixa de 400px d'ample; aquí la rajola en fa **137
 * en un iPhone de 320** —mesurat— i la cinta del panell se li menjaria el
 * monograma. Ell ja ho va dir abans de veure-ho: «la barra de la tarjeta tiene
 * que ser mucho más estrecha por necesidad».
 *
 * ── I PER QUÈ EL GANXO ÉS UN CAMP A BANDA ────────────────────────────────
 *
 * Mesurat a 11px en negreta: «10 %» demana 28px i cap; «5 % en llibres de
 * text» en demana 118 i «2x1 en la matrícula de la temporada de tardor», 252.
 * Amb 115px útils, el text llarg no hi cabia de cap manera, així que la cinta
 * només és possible amb una etiqueta curta pròpia.
 * ═══════════════════════════════════════════════════════════════════════════ */

.desc__cinta {
  display: flex;
  align-items: stretch;
  flex: none;
  height: 24px;
  background: var(--afa-crema-calida);
  /* La rajola retalla amb `overflow: hidden`, així que la cinta arriba als
     caires sense que calgui repetir-li el radi. */
  margin: 0 0 2px;
}

/*
 * La falca. El tall en diagonal és el mateix gest que la del panell, fet amb
 * `clip-path` i no amb una vora inclinada: així el color arriba de debò fins
 * al caire esquerre i no queda un píxel de fons entre la falca i la vora.
 *
 * ES PINTA SEMPRE, TINGUI GANXO O NO — i això ho va demanar David: *«Si no hay
 * "gancho" barra sin texto, pero dibujada.»* Ho va haver de repetir mirant-ho
 * al seu mòbil: *«Forn de pa Sant Pere no tiene nada indicado en la franja
 * oscura… no cumple el "siempre visto" el lado oscuro.»*
 *
 * AQUÍ HI DEIA EL CONTRARI, i convé deixar escrit què deia: «només es pinta si
 * hi ha ganxo… una falca taronja buida no es llegeix com un disseny, es
 * llegeix com una cosa que no ha carregat». Era un raonament meu sobre una
 * cosa que ell ja havia decidit, i a més no és el que passa: **la falca és una
 * peça del disseny i no una conseqüència del contingut** —el mateix motiu pel
 * qual talla al 50 % i no pel text— així que es dibuixa encara que no tingui
 * res a dir. El que trenca el mosaic és que una rajola de cada tres no tingui
 * el costat fosc.
 *
 * SENSE TEXT SEGUEIX MESURANT LA MEITAT gràcies a `flex: 0 0 50%`: la base va
 * declarada, així que no es tanca al que mesuri el contingut. Amb un `flex: 1`
 * o amb la base a `auto`, una falca buida hauria col·lapsat a zero i el defecte
 * hauria tornat per una altra porta.
 */
.desc__ganxo {
  display: flex;
  align-items: center;
  /*
   * LA FALCA OCUPA MITJA CINTA, I NO EL QUE MESURI EL TEXT.
   *
   * Ho va demanar David el 19 de setembre de 2026: *«la cinta haz que corte el
   * color al 50 % en lugar del tamaño que tiene ahora mismo»*. I té raó de
   * composició: amb la falca mesurant-se pel text, dues rajoles de costat
   * tallaven el color a llocs diferents —«10 %» i «2x1 caps de setmana» no
   * mesuren igual— i el mosaic es llegia desigual. Amb la meitat fixa, el
   * tall cau al mateix punt a totes i la cinta passa a ser una forma del
   * disseny en comptes d'una conseqüència del contingut.
   *
   * El preu, mesurat i no estimat: ver `docs/DESCOMPTES-I-PARTNERS.md`. Amb
   * mitja cinta el ganxo té menys espai que el camp permet, així que un ganxo
   * llarg es talla. Es talla i no s'amaga: el que es veu és el principi, que
   * és la part que informa.
   */
  flex: 0 0 50%;
  padding: 0 11px 0 8px;
  background: var(--afa-taronja-700);
  color: var(--afa-blanc);
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-molt);
  letter-spacing: .03em;
  white-space: nowrap;
  overflow: hidden;
  clip-path: polygon(0 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
}

/*
 * El temps. Va a la dreta i buit quan no sabem on és la persona — i buit vol
 * dir literalment sense text, no amagat: la cinta s'ha de dibuixar igual, que
 * és el que David va demanar.
 *
 * ── I QUAN NO HI CAP, ES TALLA PEL FINAL I NO PEL PRINCIPI ───────────────
 *
 * Això era un `display: flex` amb `justify-content: flex-end`, i amb el text
 * en temps va deixar de ser inofensiu: un contenidor flex alineat a la dreta
 * que desborda **retalla pel començament**, així que «aquí mateix» sortia com
 * a «uí mateix». Mesurat en un navegador de debò a 320 px.
 *
 * Amb un bloc alineat a la dreta el que sobra se'n va cap a la dreta i el que
 * queda és el PRINCIPI, que és la part que informa — la mateixa regla que ja
 * hi ha escrita per al ganxo llarg unes línies més amunt. El centrat vertical
 * el fa `line-height`, que aquí és exacte perquè la cinta té una alçada fixa
 * de 24px declarada a `.desc__cinta`.
 *
 * AIXÒ NO ARREGLA QUE «aquí mateix» NO HI CÀPIGA: mesurat, demana 76,8 px i la
 * meitat de la cinta no en dona mai més de 75 (a 414 px d'ample). Només fa que
 * el tall sigui llegible mentre no es decideixi què es fa — està anotat a
 * `docs/DESCOMPTES-I-PARTNERS.md`.
 */
.desc__temps {
  flex: 1;
  min-width: 0;
  line-height: 24px;
  text-align: right;
  padding: 0 8px;
  color: var(--afa-taronja-700);
  font-size: var(--afa-mida-xs);
  font-weight: var(--afa-pes-fort);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
}

/*
 * El cos de la rajola. Existeix perquè la cinta és una fila de dalt i la resta
 * s'ha de centrar en el que queda: sense aquest embolcall, el centrat del botó
 * centraria també la cinta i la despegaria del caire.
 */
.desc__cos {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 2px 8px 8px;
  text-align: center;
  overflow: hidden;
}

/* ──────────────────────────────────────────────────────────────────────────
 * EL FLAIX D'UNA ENTITAT COL·LABORADORA
 *
 * Encàrrec de David del 19 de setembre: que una entitat nova pugui sortir a la
 * pantalla principal del carnet, a més de l'avís push.
 *
 * ── ON VA, QUE ÉS LA DECISIÓ SENCERA ─────────────────────────────────────
 *
 * *«El flash lo cargaría por encima de todo, como si fuera un z-index +5000,
 * siempre respetando la botonera inferior y la cabecera superior intactas, que
 * no solape esas áreas.»*
 *
 * Per això NO és `position: fixed; inset: 0` com la fitxa d'un comerç o la
 * guia d'instal·lar, que tapen la pantalla sencera. Es mesura contra
 * `.flaix-ancora` —el cos de la pantalla, el que queda entre la capçalera i la
 * barra— i geomètricament no pot arribar a cap de les dues. El `z-index` alt,
 * doncs, no fa res que la caixa no faci ja; hi és perquè el projecte té una
 * escala (contingut 10 · full 19 · barra 20 · modal 30 · coberta 40) i aquesta
 * capa n'ha de quedar per damunt dins del seu tros.
 *
 * ── EL CONTRAST, QUE AQUÍ ÉS EL PROBLEMA DE DEBÒ ─────────────────────────
 *
 * Una foto qualsevol darrere de text blanc no compleix res: la foto la puja la
 * junta i pot ser un aparador amb el sol de cara. La sortida habitual és un vel
 * translúcid, i MESURAT no arriba: `--afa-vel` (blau-900 al 60 %) compost
 * damunt d'una foto blanca dona **#707C89**, i blanc a sobre són **4,26:1** —
 * per sota del 4,5 que demana AA. I no és un marge que s'arregli amb una mica
 * més: per passar de 4,5 cal el 62 % i per estar còmode el 82 % (8,93:1), que
 * damunt d'una foto clara ja és tapar-la — que és el que la foto ve a evitar.
 *
 * I el valor nominal no diu res: **una opacitat no és un color a part, el
 * navegador la composa**. Aquest projecte ja ho va pagar una vegada a la paleta
 * de Design, amb un `opacity: .55` que donava 1,81:1.
 *
 * AIXÍ QUE NO HI HA CAP TEXT DAMUNT DE LA FOTO. La foto és una banda de dalt i
 * tot el que es llegeix viu dins d'una caixa **opaca** de `--afa-marina`, o
 * sigui exactament les parelles que ja mesura `bin/contrast.php` per a la
 * credencial. La garantia deixa de dependre de quina foto pugi ningú: és
 * estructural, com ho és que el codi no pugui esborrar una factura.
 *
 * El vel es queda, i ara és el que diu que és: una transició perquè la foto es
 * fongui amb el marí en comptes de tallar-se amb una línia.
 * ────────────────────────────────────────────────────────────────────────── */

/*
 * L'ÀNCORA. Una classe que només fa això, i el motiu és de propietat: el
 * `position: relative` ha d'anar al cos de la pantalla, que es diu
 * `.pantalla__cos` a `tokens.css` i `.marc` a `portal.css` — dos fulls
 * compartits per les tres peces del projecte, on `app.css` no hi pinta res.
 * Tocar-los des d'aquí seria declarar dues vegades un nom que viu a un altre
 * lloc, que és el defecte que aquest projecte té anclat.
 */
.flaix-ancora { position: relative; }

.flaix {
  position: absolute;
  inset: 0;
  z-index: 5000;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /*
   * EL FONS ÉS OPAC I HI ÉS SEMPRE. Sense foto queda el marí de la casa amb el
   * monograma del comerç, que és la mateixa presentació que ja té una rajola
   * sense logotip — no un flaix a mitges. I amb foto, el marí és el que hi ha
   * per sota mentre la imatge no ha arribat: un rectangle transparent damunt
   * del carnet ensenyaria el QR a trossos durant la càrrega.
   */
  background: var(--afa-marina);
}

/*
 * LA FOTO NO ES RETALLA PER BAIX SINÓ QUE S'HI ENCABEIX: `cover` omple la
 * banda sencera i el que sobra queda fora. Aquí sí que toca, al revés que amb
 * el logotip d'un comerç —que és seu i no es pot tallar—: això és la foto d'un
 * aparador i el que importa és que ompli.
 */
.flaix__fons {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 55%;
  object-fit: cover;
}

.flaix__vel {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: 100%;
  height: 55%;
  /*
   * De transparent a marí sòlid. No defensa cap text —no n'hi ha cap a sobre—
   * així que els seus valors no van a `bin/contrast.php`: allà hi ha d'anar el
   * que algú ha de poder llegir, i una llista amb parelles decoratives és una
   * llista on la que importa passa desapercebuda.
   */
  background: linear-gradient(to bottom,
              rgba(22, 56, 90, 0) 0%,
              rgba(22, 56, 90, .45) 55%,
              var(--afa-marina) 100%);
}

.flaix__caixa {
  position: relative;
  margin-top: auto;
  max-height: 100%;
  overflow-y: auto;
  /*
   * EL FARCIMENT DE BAIX NO VA AQUÍ SINÓ A LA TIRA DE BOTONS, que és la que
   * s'enganxa al terra quan el text no hi cap. Posat aquí quedaria per sota
   * de la tira i deixaria una franja morta.
   */
  padding: var(--afa-espai-5) var(--afa-espai-4) 0;
  /*
   * OPACA, i això és la garantia de contrast. Mira la capçalera d'aquest bloc.
   */
  background: var(--afa-marina);
  /*
   * I amb el marí escampat cap amunt, perquè quan el text és llarg la caixa
   * puja per dins de la banda de la foto i el caire quedaria com una línia
   * recta enmig de la imatge. L'ombra hi posa un pam de degradat i no toca res
   * del que es llegeix, que segueix damunt d'un fons sòlid.
   */
  box-shadow: 0 -2rem 2rem -.5rem var(--afa-marina);
}

/*
 * SENSE FOTO, LA CAIXA VA CENTRADA. Enganxada a baix deixaria una banda marina
 * buida a dalt que es llegeix com una imatge que no ha acabat de carregar —el
 * mateix motiu pel qual una llista buida s'amaga a més de buidar-se.
 */
.flaix:has(> .flaix__fons[hidden]) .flaix__caixa { margin-block: auto; }

/* El monograma i el nom de l'entitat, en una línia. */
.flaix__marca {
  display: flex;
  align-items: center;
  gap: var(--afa-espai-3);
  margin: 0 0 var(--afa-espai-3);
  min-width: 0;
}

/*
 * El forat del monograma. `.desc__inicials` l'omple i ja porta el seu tint
 * mesurat (taronja-050 amb tinta blau-700, 10,59:1); aquí només se li diu
 * quant espai té.
 */
.flaix__marca .desc__inicials,
.flaix__marca .desc__logo {
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
}

.flaix__marca strong {
  min-width: 0;
  color: var(--afa-blanc);
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-fort);
  /* Un nom llarg d'una sola paraula no pot eixamplar la capa. */
  overflow-wrap: anywhere;
}

.flaix__titol {
  margin: 0 0 var(--afa-espai-2);
  color: var(--afa-blanc);
  font-size: var(--afa-mida-l);
  font-weight: var(--afa-pes-molt);
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.flaix__cos {
  margin: 0 0 var(--afa-espai-3);
  color: var(--afa-blau-200);
  font-size: var(--afa-mida-s);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/*
 * El descompte, amb el taronja de la credencial. És el mateix valor dit al
 * mateix to que a la targeta, i surt UNA vegada: el ganxo només fa de recanvi.
 */
.flaix__oferta {
  margin: 0 0 var(--afa-espai-4);
  color: var(--afa-taronja-300);
  font-size: var(--afa-mida-m);
  font-weight: var(--afa-pes-molt);
  overflow-wrap: anywhere;
}

/*
 * DOS BOTONS DE VERITAT, no una aspa de dotze píxels a una cantonada. Tancar
 * és la meitat d'aquesta pantalla i ha de ser tan fàcil com entrar-hi.
 *
 * `1fr auto` i no un flex amb `flex: 1`: amb el flex, el botó del rètol més
 * llarg s'emporta més ample i els dos ballen segons l'idioma.
 */
.flaix__accions {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--afa-espai-3);
  align-items: stretch;
  /*
   * ── I S'ENGANXEN AL TERRA DE LA CAIXA ────────────────────────────────────
   *
   * MESURAT, i era un defecte de veritat: amb el text màxim que admet la base
   * —títol de 80 i cos de 300— en un telèfon de **320x568** la caixa demana
   * 526px i només en té 443, així que es desplaça per dins… i els dos botons
   * queden a 515px, **fora de la pantalla**. O sigui que el botó de tancar el
   * flaix no es veia i calia endevinar que allò es podia desplaçar.
   *
   * Enganxats, sempre hi són. El fons opac és el que fa que el text hi passi
   * per sota sense barrejar-s'hi, i el farciment de baix el porten ells
   * —vegeu `.flaix__caixa`— perquè entre la tira i el caire no quedi un forat.
   */
  position: sticky;
  bottom: 0;
  padding-top: var(--afa-espai-3);
  padding-bottom: var(--afa-espai-5);
  background: var(--afa-marina);
}

.flaix__anar,
.flaix__tanca {
  /*
   * El terra tàctil del projecte. Els 24px d'AA són el mínim absolut; aquí es
   * fan servir els 48 de `--afa-tap-min`, que és el que ja compleix la resta.
   */
  min-height: var(--afa-tap-min);
  padding: var(--afa-espai-3) var(--afa-espai-4);
  border-radius: var(--afa-radi-m);
  font-family: inherit;
  font-size: var(--afa-mida-s);
  font-weight: var(--afa-pes-fort);
  cursor: pointer;
}

.flaix__anar {
  background: var(--afa-blanc);
  border: 0;
  color: var(--afa-blau-900);
}

/*
 * Tancar va buit i amb la vora clara: es veu, es toca i no competeix amb el
 * botó que l'anunci ve a demanar. Blanc sobre marí és la parella AAA de la
 * credencial, o sigui que ja està mesurada.
 */
.flaix__tanca {
  background: none;
  border: 1px solid var(--afa-vora-clara);
  color: var(--afa-blanc);
}

/*
 * A partir de 30rem la capa deixa de ser tota la pantalla i el text es queda en
 * una columna llegible: una línia de 600px de llarg no la segueix ningú.
 */
@media (min-width: 30rem) {
  .flaix__caixa {
    width: 100%;
    max-width: 32rem;
    margin-inline: auto;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * EL CONVIT A UN COMERÇ — un document i un formulari, no una entrada
 *
 * `.login` està feta per a una pantalla d'entrada en un mòbil: 24rem de
 * columna i tot centrat. Aquí això és fals per partida doble.
 *
 * PRIMER, PER QUI HI ARRIBA. La família entra al carnet des del telèfon; un
 * comerç omple aquest formulari **des de l'ordinador de la botiga**, perquè és
 * on té el logotip que ha de pujar. És l'única pantalla de tot el carnet on
 * l'escriptori és el cas normal i no l'excepció.
 *
 * I SEGON, PEL QUE HI HA. Sis línies d'acord, un enllaç al text sencer i set
 * camps. Un text llarg centrat es llegeix pitjor com més ample és la pantalla:
 * l'ull perd la vora esquerra a cada salt de línia.
 *
 * 46rem i no més: per sobre de ~75 caràcters per línia la lectura torna a
 * caure, i això és un document que algú ha de llegir abans de signar.
 *
 * ── I TRES CLASSES QUE NO PINTAVEN RES ──────────────────────────────────
 *
 * La pantalla duia `g__grup`, `g__ajuda` i `llista-simple`. Les dues primeres
 * viuen a `gestio.css`, que aquesta pàgina NO carrega; la tercera no existeix
 * enlloc —a `gestio.css` es diu `g__llista-simple`—. O sigui que el resum de
 * l'acord es servia com a HTML pelat, amb els pics per omissió i centrats.
 *
 * No es resol carregant `gestio.css`: portaria el full sencer del panell de la
 * junta a una pàgina pública per tres regles. Es resol amb noms propis al full
 * que aquesta pàgina ja carrega, que és el que el projecte té escrit.
 * ═══════════════════════════════════════════════════════════════════════════ */

.login--doc {
  max-width: 46rem;
  text-align: left;
}

/* La marca i el nom del comerç sí que van centrats: són la capçalera. */
.login--doc .login__marca,
.login--doc .login__titol { text-align: center; }

/*
 * I EL NOM DEL COMERÇ ÉS EL TÍTOL DE LA PÀGINA, no un subtítol.
 *
 * `.login__titol` és gris i prim perquè a l'entrada del carnet diu «Entra amb
 * el teu correu», que acompanya la marca. Aquí diu «Lacapsadefotos»: és la
 * primera confirmació que qui obre l'enllaç ha arribat al lloc que toca, i amb
 * el gris suau semblava un peu de foto.
 */
.login--doc .login__titol {
  font-size: var(--afa-mida-l);
  font-weight: var(--afa-pes-fort);
  color: var(--afa-text);
  margin-bottom: var(--afa-espai-3);
}

.login--doc .login__ajuda { text-align: left; }

/*
 * El resum de l'acord, dins d'una caixa. No és decoració: separa el que el
 * comerç ACCEPTA del que el comerç ESCRIU, que són les dues meitats de la
 * pàgina i abans es llegien seguides.
 */
.convit__resum {
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
  padding: var(--afa-espai-4);
  margin: 0 0 var(--afa-espai-6);
}

.convit__llista { list-style: none; margin: 0; padding: 0; }

.convit__llista li {
  padding: var(--afa-espai-2) 0;
  border-bottom: 1px solid var(--afa-gris-100);
}

.convit__llista li:last-child { border-bottom: 0; }

/* L'ajuda d'un camp (`.camp__pista`) viu a `tokens.css`: la comparteixen
   el panell i aquesta pàgina. */

/*
 * L'AVANTATGE JA ACORDAT es llegeix, no s'escriu: el va pactar qui va parlar
 * amb la botiga i aquí només es confirma. Va destacat perquè és l'única dada
 * de la pàgina que el comerç no pot canviar, i té dret a veure-la clara.
 */
/*
 * ── EL RÈTOL DE CADA DADA QUE JA TENIM ───────────────────────────────────
 *
 * `.camp__etiqueta` va pensada per encapçalar un camp que s'escriu, i aquí
 * encapçala una dada que només es llegeix: sense aire per sobre, les tres
 * quedaven enganxades a la caixa anterior i semblava que en formessin part.
 */
.convit__rotul { margin-top: var(--afa-espai-5); }

/*
 * Les condicions: el mateix full que l'avantatge però sense el pes, perquè
 * són la lletra petita del tracte i no el tracte.
 */
.convit__condicions {
  background: var(--afa-crema);
  border-radius: var(--afa-radi-s);
  padding: var(--afa-espai-3) var(--afa-espai-4);
  margin: 0 0 var(--afa-espai-5);
  white-space: pre-line;
  color: var(--afa-text-suau);
  font-size: var(--afa-mida-s);
}

/*
 * EL LOGOTIP, SOBRE BLANC I AMB VORA.
 *
 * Aquí no es pinta «una imatge»: es pinta COM QUEDA al carnet, i al carnet la
 * rajola és blanca. Sobre el crema de la pàgina, un logotip amb fons
 * transparent es veuria damunt d'un color que no és el que tindrà mai — i
 * aquesta pantalla existeix justament perquè el comerç vegi el que hi ha.
 *
 * `object-fit: contain` i no `cover`: retallar el logotip d'algú per omplir un
 * quadre és pitjor que deixar-hi aire.
 */
.convit__logo {
  margin: 0 0 var(--afa-espai-5);
}

.convit__logo img {
  display: block;
  width: 160px;
  height: 160px;
  object-fit: contain;
  background: var(--afa-blanc);
  border: 1px solid var(--afa-vora);
  border-radius: var(--afa-radi-m);
  padding: var(--afa-espai-3);
}

/*
 * ── LA CAPA DE PROTECCIÓ DE DADES ────────────────────────────────────────
 *
 * Va abans de la casella i amb menys pes que el cos: és el que la llei demana
 * dir en el moment de recollir les dades, no un reclam. Però NO va amagada
 * dins d'un desplegable: una informació que cal obrir per veure no és
 * informació donada.
 */
.convit__rgpd {
  border-top: 1px solid var(--afa-vora);
  padding-top: var(--afa-espai-4);
  margin: var(--afa-espai-5) 0 var(--afa-espai-4);
  font-size: var(--afa-mida-s);
  color: var(--afa-text-suau);
}

.convit__rgpd p { margin: 0 0 var(--afa-espai-2); }
.convit__rgpd p:last-child { margin-bottom: 0; }

/*
 * El «no m'ha arribat»: un formulari sencer perquè és un POST, i ha de
 * semblar el que és —una sortida, no l'acció principal—. Per això va sota del
 * botó i amb `boto--text`.
 */
.convit__reenvia {
  margin-top: var(--afa-espai-4);
  text-align: center;
}

.convit__avantatge {
  background: var(--afa-crema);
  border-radius: var(--afa-radi-s);
  padding: var(--afa-espai-3) var(--afa-espai-4);
  margin: 0 0 var(--afa-espai-5);
  white-space: pre-line;
  font-weight: var(--afa-pes-fort);
}
