/* Cerler: sistema de diseño.
 *
 * Identidad: casa de montaña en el Pirineo. Nieve, piedra y pino, no panel SaaS.
 * Cero webfonts: una webfont son 25-60 KB, una petición más y un FOUT visible
 * justo en el escenario que más importa, que es abrir la app en el pueblo con
 * una barra de cobertura. La personalidad la da ui-serif del sistema (Georgia
 * en Android, New York en iOS) en titulares y nombres de mes; el resto va en
 * system-ui, y los NÚMEROS siempre en sans (regla de la skill dataviz: la cifra
 * protagonista nunca en serif).
 *
 * Contrato de tema: :root es el claro y [data-tema="oscuro"] lo pisa. El JS
 * fija SIEMPRE data-tema a claro u oscuro, nunca a auto: auto se resuelve antes
 * con matchMedia. Hay un snippet inline en el <head> que lo aplica antes de
 * pintar, para que no haya destello.
 *
 * ESCALA TIPOGRÁFICA: cinco pasos y ni uno más. Antes había ~20 tamaños puestos
 * a ojo y h2 medía 16,8 px sobre un cuerpo de 16, o sea que no había jerarquía:
 * todo pesaba igual y la pantalla no se dejaba escanear. Los pasos van en `rem`
 * multiplicados por --escala, no en `em`, para que no compongan al anidarse.
 * Prohibido escribir un font-size que no salga de estos tokens.
 *
 * TAMAÑO DE TEXTO: html va en 100% y, donde exista, en `-apple-system-body`, que
 * es lo que respeta el Dynamic Type de iOS. Encima va --escala, el control de
 * tres pasos de Ajustes, porque en la PWA instalada NO existe el menú aA de
 * Safari y sin esto no hay ninguna forma de agrandar la letra.
 *
 * COLORES DE PERSONA (--p1..--p7): tope declarado de 7 slots. Re-escalonados en
 * julio de 2026 y validados con scripts/validate_palette.js de la skill dataviz
 * en los dos temas y con el pairlist de TODOS los pares (que es el que toca: el
 * calendario dispersa los colores por la rejilla, no los pone en barras
 * adyacentes). Resultado: claro ΔE normal 17,2 / CVD 8,6; oscuro ΔE normal 15,4
 * / CVD 8,3, con banda de luminosidad, suelo de croma y contraste en verde.
 * Los anteriores fallaban de tres formas: el lago y el glaciar tenían ΔE 9,6 con
 * visión NORMAL (suelo 15), con deuteranopía el lago y la genciana eran el mismo
 * color (ΔE 1,4), y en oscuro los siete estaban por encima de la banda, todos en
 * la misma luminosidad, así que el tema oscuro se veía plano.
 *
 * REGLA DURA, sin excepciones: el color de una persona NUNCA lleva texto encima.
 * El número del día va sobre un velo del color de la tarjeta, los nombres van al
 * lado del color y la inicial va sobre el velo. Y el color nunca va solo: cada
 * estancia lleva la INICIAL de la persona en su celda de inicio, que es la
 * codificación secundaria que exige la skill.
 */

:root {
  color-scheme: light;

  --lienzo:    #f7f4ef;   /* plano de página, cálido: nieve sucia, no blanco clínico */
  --lienzo-2:  #efe9e1;
  --tarjeta:   #ffffff;
  --tarjeta-2: #fbf9f6;   /* tarjeta elevada, para que algo pueda flotar sobre otra */
  --tinta:     #1b2126;
  --tinta-2:   #4d565e;   /* 7,5:1 sobre tarjeta: es tinta de DATO, no de adorno */
  --tinta-3:   #67717a;   /* 5,0:1 sobre tarjeta y 4,5:1 sobre lienzo: solo adorno */
  --borde:     #c2b6a4;   /* 2,0:1 sobre tarjeta. Antes 1,33:1, o sea invisible */
  --borde-2:   #8d7e68;   /* 3,9:1 sobre tarjeta: el de los campos de formulario */
  --velo:      rgba(255,255,255,.86);   /* el velo que va encima del color de persona */
  --andamio:   #d6c9b4;   /* "hueco medible": la parte vacía de una barra o rejilla */

  --acento:       #2d6a55;   /* pino */
  --acento-fondo: #dcebe4;
  --acento-tinta: #ffffff;
  --foco:         #14483a;

  /* semáforo, reutilizable por dominio (libre / a medias / ocupado) */
  --si:      #24704a;
  --si-fondo:#dcefe2;
  --ojo:     #8c5f06;
  --ojo-fondo:#f6e7c8;
  --no:      #a53c37;
  --no-fondo:#f7ddda;

  /* superficie sobre la que se validaron los colores de persona */
  --lienzo-grafico: var(--tarjeta);

  --p1: #18568e;  /* azul lago  */
  --p2: #88390b;  /* teja       */
  --p3: #14833e;  /* prado      */
  --p4: #7e64d0;  /* genciana   */
  --p5: #aa8f13;  /* ocre       */
  --p6: #139cb6;  /* glaciar    */
  --p7: #ca5677;  /* frambuesa (slot compartido de invitados) */

  --radio:   14px;
  --radio-s: 9px;
  --radio-l: 20px;

  /* TRES niveles de sombra. Con una sola para todo, nada flotaba: una hoja modal
   * y una tarjeta en reposo tenían la misma elevación y el cerebro no sabía qué
   * estaba encima de qué. */
  --sombra-1: 0 1px 2px rgba(27,33,38,.05);
  --sombra-2: 0 2px 4px rgba(27,33,38,.07), 0 8px 20px rgba(27,33,38,.08);
  --sombra-3: 0 -2px 8px rgba(27,33,38,.08), 0 -18px 48px rgba(27,33,38,.18);

  --sans:  system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --serif: ui-serif, Georgia, "Times New Roman", serif;

  /* --- escala tipográfica: CINCO pasos --- */
  --escala: 1;
  --t1: calc(1.6rem  * var(--escala));   /* titular de pantalla */
  --t2: calc(1.25rem * var(--escala));   /* h2, título de tarjeta */
  --t3: calc(1rem    * var(--escala));   /* cuerpo */
  --t4: calc(.875rem * var(--escala));   /* secundario, listas densas */
  --t5: calc(.75rem  * var(--escala));   /* pistas, etiquetas, pie */
  /* La cifra protagonista no es un paso más de la escala de texto: es un dato,
   * y va en sans con su propio tamaño. */
  --t-cifra:  calc(2.4rem * var(--escala));
  --t-cifra2: calc(1.55rem * var(--escala));
  --t-hero:   calc(1.85rem * var(--escala));

  /* Las publica js/nucleo.js midiendo los elementos de verdad. Los valores de
   * aquí son solo el arranque antes del primer ResizeObserver. */
  --alto-cabecera: 54px;
  --alto-nav: 62px;

  /* ANCHO DE LECTURA. Un solo número para las DOS columnas que tienen que caer
   * en el mismo sitio: el contenido de la cabecera (.superior-caja) y el cuerpo
   * (main). Estaba escrito a mano en un único sitio, main, así que la fila
   * L M X J V S D de la cabecera se iba a la anchura de la ventana y a 1280 px
   * la "S" caía sobre el día 23 y la "D" sobre nada. Nadie vuelve a escribir
   * 46rem: si hay que cambiarlo, se cambia aquí y se mueven las dos.
   * Por debajo de 780 px no se aplica (las dos van a lo ancho de la pantalla),
   * que es justo por lo que en el móvil el desvío no se veía. */
  --ancho-lectura: 46rem;

  /* Relleno lateral compartido por main y por la caja de la cabecera. Si uno
   * mete 16 y el otro 14, la rejilla y los días vuelven a bailar 2 px: hoy hay
   * un apaño de `margin-inline: -2px` en .cal-barra-dias que existe justo por
   * eso y que este token deja sin trabajo. env() por el notch en apaisado. */
  --respiro-izq: max(14px, env(safe-area-inset-left));
  --respiro-der: max(14px, env(safe-area-inset-right));

  /* La navegación lateral del escritorio. 0 en el móvil, donde la barra sigue
   * abajo; las cuentas de los elementos fijos (barra de selección, avisos, hoja)
   * se escriben una sola vez y valen para los dos sitios. */
  --nav-lateral: 0px;
}

[data-tema="oscuro"] {
  color-scheme: dark;

  --lienzo:    #12161b;
  --lienzo-2:  #171c22;
  --tarjeta:   #1b2027;
  --tarjeta-2: #222831;
  --tinta:     #e9edf1;
  --tinta-2:   #a4b0ba;   /* 7,4:1 sobre tarjeta */
  --tinta-3:   #8b98a4;   /* 5,6:1 sobre tarjeta */
  --borde:     #414c58;   /* 1,9:1 */
  --borde-2:   #6b7a86;   /* 3,7:1 */
  --velo:      rgba(15,19,24,.82);
  --andamio:   #3a4450;

  --acento:       #6fbfa3;
  --acento-fondo: #17332c;
  --acento-tinta: #06120e;
  --foco:         #9bdcc4;

  --si:      #63cf93;  --si-fondo:  #123020;
  --ojo:     #e4b054;  --ojo-fondo: #2e2411;
  --no:      #f3837c;  --no-fondo:  #331815;

  --lienzo-grafico: var(--tarjeta);

  --p1: #186ad4;
  --p2: #b74f13;
  --p3: #268255;
  --p4: #9778f5;
  --p5: #a9912b;
  --p6: #2ea0c3;
  --p7: #d74686;

  --sombra-1: 0 1px 2px rgba(0,0,0,.4);
  --sombra-2: 0 2px 6px rgba(0,0,0,.45), 0 10px 26px rgba(0,0,0,.35);
  --sombra-3: 0 -2px 10px rgba(0,0,0,.5), 0 -20px 52px rgba(0,0,0,.55);
}

* { box-sizing: border-box; }

/* [hidden] TIENE que ocultar. El navegador lo hace con `[hidden]{display:none}`
 * desde su hoja de agente de usuario, pero CUALQUIER regla de autor que declare
 * `display` la machaca: el origen del autor gana al del navegador antes incluso
 * de mirar la especificidad. Pasó con .barra-seleccion{display:flex}, que dejó
 * una franja blanca visible en las cinco pantallas y un botón "Quitar" que no
 * ocultaba nada. Esta línea blinda todos los `hidden` del proyecto. */
[hidden] { display: none !important; }

/* Sin esto, iOS pinta su destello translúcido en cada toque, que sobre una celda
 * del calendario compite con la selección de verdad. */
* { -webkit-tap-highlight-color: transparent; }

/* Quita el retardo de ~300 ms que iOS espera por si viene un doble toque. Es la
 * mejora de sensación más barata de toda la app. */
a, button, label, input, .cal-dia { touch-action: manipulation; }

/* Una pulsación larga de papá sobre un día del calendario le sacaba LA LUPA de
 * iOS y el menú de selección de texto en vez de elegir el día. Se apaga en todo
 * lo que se toca; se deja activa en los textos que uno puede querer copiar (el
 * libro de la casa, el enlace del calendario). */
button, .cal-dia, .nav-item, .hoja-asa, .heat-fila, .marcas label, .barras,
.pastilla-agenda, .conmutador, .lista-elegir button {
  -webkit-user-select: none; user-select: none;
}

html {
  -webkit-text-size-adjust: 100%;
  font-size: 100%;
  /* Sin esto, en iOS el "rebote" del final de la página arrastra la barra de
   * navegación y en Android el scroll se propaga al fondo. */
  overscroll-behavior-y: none;
}
/* Respeta el tamaño de letra del sistema. En iPhone es la única forma de que el
 * Dynamic Type llegue a una PWA: dentro de la app instalada no hay menú aA. */
@supports (font: -apple-system-body) {
  html { font: -apple-system-body; font-family: var(--sans); }
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--t3);
  line-height: 1.5;
  color: var(--tinta);
  background: var(--lienzo);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
  /* la PWA va con viewport-fit=cover; sin esto el contenido se mete bajo el notch */
  padding: max(20px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right))
           max(20px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left));
}

h1, h2, h3, .serif { font-family: var(--serif); font-weight: 600; letter-spacing: -.01em; }
h1 { font-size: var(--t1); margin: 0 0 .25em; line-height: 1.2; }
h2 { font-size: var(--t2); margin: 0 0 .45em; line-height: 1.25; }
h3 { font-size: var(--t3); margin: 0 0 .3em; }

.envoltorio { max-width: 34rem; margin: 12vh auto 0; }

.card {
  background: var(--tarjeta);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  box-shadow: var(--sombra-1);
  /* 20 y no 28: en un iPhone de 390 px quedan 358 útiles y 28 de padding se
   * comía 56, o sea un 16% del ancho de la pantalla en aire. */
  padding: 20px;
}
@media (min-width: 480px) { .card { padding: 26px; } }

.sub { color: var(--tinta-2); font-size: var(--t4); margin: 0 0 1.2em; }
.pie { margin-top: 1.5rem; font-size: var(--t5); color: var(--tinta-3); }
.pista { font-size: var(--t5); color: var(--tinta-3); margin-top: .4rem; }
.traza { white-space: pre-wrap; word-break: break-word; font-family: ui-monospace, Menlo, monospace; }
.nota { font-style: italic; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88em; }

.marca {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--serif); font-size: var(--t3); color: var(--tinta-2);
  margin-bottom: 1.75rem;
}
.marca svg { display: block; }

.lista { list-style: none; padding: 0; margin: 1.5rem 0 0; }
.lista li {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .55rem 0; border-top: 1px solid var(--borde);
  color: var(--tinta-2); font-size: var(--t4);
}
.lista li:first-child { border-top: 0; }
.lista b { color: var(--tinta); font-weight: 600; }

/* --- FOCO. Visible en TODO lo enfocable, no solo en las celdas del calendario.
 * Anillo doble: el interior con el color de acento y el exterior del color de la
 * superficie, para que se vea igual sobre una tarjeta blanca que sobre el color
 * de una persona. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--foco);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--tarjeta);
}
/* Los navegadores viejos que no entienden :focus-visible no se quedan sin foco. */
@supports not selector(:focus-visible) {
  :where(a, button, input, textarea, select, [tabindex]):focus {
    outline: 3px solid var(--foco); outline-offset: 2px;
  }
}

/* Un <input type="file"> con `hidden` NO es enfocable ni existe para el lector
 * de pantalla, así que "Añadir una foto" era inalcanzable con teclado o con
 * VoiceOver. Esto lo esconde a la vista dejándolo en el árbol. */
.oculto-visual {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
  .card { animation: entra .3s cubic-bezier(.22,.61,.36,1) both; }
  @keyframes entra { from { opacity: 0; transform: translateY(6px); } }
}

/* ===================================================================== app ==
 * Todo lo que sigue es la app en sí. Lo de arriba son los tokens y las
 * primitivas, que comparten index.html y entrar.html.
 */

body { padding: 0; }
#app { padding-bottom: calc(var(--alto-nav) + 12px); }

/* --- cabecera pegajosa --- */
.superior {
  position: sticky; top: 0; z-index: 30;
  /* Sin relleno lateral: el fondo velado y la raya de abajo cruzan la pantalla
   * entera, pero el CONTENIDO lo coloca .superior-caja con las mismas medidas
   * que main. Antes esto metía 16 px y main 14, que es de donde salía el
   * desfase de 2 px que había que compensar a mano. */
  padding: max(10px, env(safe-area-inset-top)) 0 8px;
  background: color-mix(in srgb, var(--lienzo) 92%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--borde);
}
/* La columna de la cabecera: mismo relleno y, en pantalla grande, mismo ancho
 * máximo y mismo centrado que main. Es la mitad del contrato; la otra mitad
 * está en la regla de main y en el bloque de escritorio. */
.superior-caja { padding-inline: var(--respiro-izq) var(--respiro-der); }
.superior-fila { display: flex; align-items: center; gap: .6rem; }
.superior .marca { margin: 0; font-size: var(--t3); color: var(--tinta); flex: 1; }
.quien { font-size: var(--t5); color: var(--tinta-2); }

/* El botón "Hoy" da función a los 45 px de la cabecera que solo llevaban el
 * logotipo, y resuelve el problema real: si te vas a mirar julio de 2028, volver
 * al presente costaba veinte pasadas de dedo. */
.btn-hoy {
  position: relative;           /* ancla del área táctil de abajo */
  font: inherit; font-size: var(--t5); font-weight: 600;
  min-height: 34px; padding: 0 .7rem; border-radius: 999px;
  color: var(--acento); background: var(--acento-fondo);
  border: 1px solid transparent; cursor: pointer;
}
/* 44 px de área táctil con 34 px de pastilla, el mismo patrón que `.hoja-asa`.
 * Subir el `min-height` funcionaría (`--alto-cabecera` sale del ResizeObserver,
 * así que los títulos pegajosos seguirían a la cabecera), pero se comería 10 px
 * permanentes de pantalla en un iPhone SE por un botón secundario. */
.btn-hoy::before {
  /* Altura EXPLÍCITA y centrada, no `top/bottom: -5px`: el bloque contenedor de
   * un pseudo-elemento absoluto es la caja de RELLENO, y este botón lleva un
   * borde de 1 px, así que estirar 5 px por arriba y por abajo daba 42 y no 44
   * (medido en Chromium). Con `height` fija da igual el borde, y centrado con
   * margen negativo se aguanta si el tamaño de texto del sistema crece. */
  content: ''; position: absolute; left: 0; right: 0;
  top: 50%; margin-top: -22px; height: 44px;
}

/* La fila L M X J V S D vive DENTRO de la cabecera cuando la ruta es el
 * calendario. Antes era un segundo elemento pegajoso con `top: 46px` a ojo: en
 * la PWA instalada de un iPhone 14 la cabecera mide 82 px por el área segura, así
 * que la fila de días se quedaba DEBAJO de la cabecera y no se veía nunca. Y
 * entre la barra de selección y la de navegación quedaba una rendija de 7 px.
 * Metiéndola en la cabecera desaparecen las dos medidas mágicas. */
.cal-barra-dias {
  display: grid; grid-template-columns: repeat(7, 1fr);
  margin-top: 8px; padding-top: 6px; border-top: 1px solid var(--borde);
  font-size: var(--t5); color: var(--tinta-2); text-align: center;
  font-variant-numeric: tabular-nums;
}
html:not([data-ruta="calendario"]) .cal-barra-dias { display: none; }
/* El botón Hoy solo tiene sentido en el calendario. */
html:not([data-ruta="calendario"]) .btn-hoy { display: none; }

/* El relleno lateral sale del mismo token que la cabecera. De paso, la izquierda
 * usa inset-left y la derecha inset-right: la versión anterior los tenía
 * cruzados (daba igual mientras el notch fuera simétrico, pero era mentira). */
main { padding: 14px 0 8px; padding-inline: var(--respiro-izq) var(--respiro-der); }
.vista > .card, .vista > .hero, .vista > .franja, .vista > .conmutador-caja { margin-bottom: 12px; }

/* Franja de "esto es de la caché". El service worker marca sus respuestas con
 * X-Cerler-Cache; sin decirlo, la app enseña el calendario de ayer como si fuera
 * el de hoy, que en una casa con varios escritores es mentir. */
.franja {
  display: flex; align-items: center; gap: .5rem;
  padding: .6rem .8rem; border-radius: var(--radio-s);
  font-size: var(--t4); background: var(--ojo-fondo); color: var(--ojo);
  border: 1px solid color-mix(in srgb, var(--ojo) 30%, transparent);
}
.franja svg { flex: none; width: 18px; height: 18px; fill: currentColor; }

/* ===================================================================== hero ==
 * La escena del valle. El texto va SIEMPRE sobre un velo oscuro, nunca
 * directamente sobre el dibujo: con el día despejado y el valle nevado el fondo
 * es casi blanco y el texto blanco desaparecería.
 *
 * PERO EL VELO NO PUEDE COMERSE LA ESCENA. La versión anterior lo ponía sobre
 * el hero ENTERO empezando ya en .55 arriba, y con razón: el bloque de texto
 * ocupaba el hero de arriba abajo, así que tapar donde hay texto era tapar
 * todo. El resultado era que a las dos de la tarde de un día de sol el cielo
 * salía gris de tormenta. La escena estaba, pero no se veía ninguna de las tres
 * cosas que la hacen valer (estación, tiempo y hora).
 *
 * El arreglo son dos cosas juntas:
 *   1. el hero es MÁS ALTO, así que el texto vive en la mitad de abajo;
 *   2. el velo ya no es del hero, es el FONDO del bloque de texto, y su rampa
 *      es el relleno de arriba de ese bloque. Así el velo va siempre pegado al
 *      texto pase lo que pase: si el titular ocupa dos líneas, o si alguien
 *      pone la letra en "enorme", la rampa se mueve con él en vez de quedarse
 *      donde estaba. Arriba del bloque no hay velo: ahí se ve el cielo tal cual.
 * Lo mide `comprueba_contraste_hero` en tools/cerler_e2e.py sobre los píxeles
 * que de verdad se pintan, no sobre este CSS.
 */
.hero {
  position: relative; overflow: hidden;
  border-radius: var(--radio); box-shadow: var(--sombra-2);
  min-height: 17rem; display: flex; flex-direction: column; justify-content: flex-end;
  isolation: isolate;
}
/* En pantalla grande el SVG (2:1) se recorta por arriba y por abajo, así que
 * cuanto más alto es el hero más trozo de valle entra. */
@media (min-width: 780px) { .hero { min-height: 19rem; } }
.hero-escena { position: absolute; inset: 0; z-index: 0; }
.escena { display: block; width: 100%; height: 100%; }
.escena-foto { object-fit: cover; }
/* EL CUADRO DEL PADRE DE KIKO necesita decidir qué se pierde, y no es lo mismo
 * en el móvil que en el Mac.
 *   - El cuadro es 4:3 (1,35:1) y el hero en un móvil mide 1,33:1. Casi el mismo
 *     encuadre, así que ahí `cover` no recorta nada: se ve ENTERO, con el cielo,
 *     las cimas, la casa y el hombre del haz. Por eso aquí no se toca nada.
 *   - En escritorio el hero se estira a unos 2,9:1, así que hay que tirar un
 *     tercio del alto. Se conserva la banda de abajo (la casa de piedra y el
 *     hombre, que son el motivo) y se va el cielo. Al revés se perdía lo único
 *     que hace que el cuadro sea de esta casa y no de cualquier valle.
 * El 78% y no el 100% para que el borde inferior del lienzo no toque el canto. */
@media (min-width: 780px) {
  .escena-foto.escena-cuadro { object-position: center 78%; }
}

/* La foto del salón, arriba del Libro. Con el mismo radio y la misma sombra que
 * una tarjeta, para que forme parte de la pila y no parezca pegada encima. */
.libro-foto {
  margin: 0 0 12px; border-radius: var(--radio); overflow: hidden;
  box-shadow: var(--sombra-1); background: var(--lienzo-2);
}
.libro-foto img {
  display: block; width: 100%; height: auto;
  /* 4:3 declarado para que el hueco esté reservado ANTES de que baje la imagen:
   * si no, al llegar la foto empuja la checklist hacia abajo y se toca un
   * checkbox que ya no está donde estaba. */
  aspect-ratio: 4 / 3; object-fit: cover;
}
/* El velo, y el porqué de cada parada:
 *   0 -> 24px    transparente: el cielo entero, sin tocar.
 *   24 -> 72px   la rampa. Aquí caen las crestas, que son siluetas oscuras y se
 *                siguen leyendo perfectamente a media opacidad.
 *   72px         .66, que es donde empieza la primera línea de texto.
 *   100%         .82 abajo, donde está el suelo del valle y los botones.
 * Las paradas NO salen de una cuenta a mano: son las que el arnés mide y da por
 * buenas. Con estas, lo más justo de las 60 medidas es 6,5:1 sobre los 4,5 que
 * exige AA, y le toca al primer renglón del hero de Montaña a 320 px con el
 * valle nevado a mediodía. Si se bajan, la comprobación lo dice con la cifra. */
.hero-texto {
  position: relative; z-index: 2; padding: 72px 20px 20px; color: #fff;
  background: linear-gradient(to bottom,
    rgba(8,12,18,0) 0, rgba(8,12,18,.06) 24px, rgba(8,12,18,.34) 50px,
    rgba(8,12,18,.66) 72px, rgba(8,12,18,.82) 100%);
}
/* La sombra no cuenta para AA (el velo ya se encarga), pero es lo que hace que
 * las líneas finas no "vibren" contra el degradado del cielo. */
.hero-texto .sub { color: rgba(255,255,255,.92); margin: 0; text-shadow: 0 1px 2px rgba(8,12,18,.5); }
.hero h1 { font-size: var(--t-hero); margin: .05em 0 .25em; color: #fff;
  text-shadow: 0 1px 3px rgba(8,12,18,.4); }
.hero-alto {
  margin: 0 0 .1em; font-size: var(--t5); letter-spacing: .09em; text-transform: uppercase;
  color: #fff; font-weight: 700; text-shadow: 0 1px 2px rgba(8,12,18,.5);
}
/* Cifra protagonista: grande, en sans y en blanco sobre el velo. */
.hero-cifra {
  font-family: var(--sans); font-size: var(--t-cifra); font-weight: 680;
  line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  display: block; margin: .1em 0 .05em; color: #fff;
  text-shadow: 0 1px 3px rgba(8,12,18,.4);
}
.hero-cifra small { font-size: .38em; font-weight: 600; opacity: .9; margin-left: .25em; }
.hero-acciones { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .9rem; }

/* Las tarjetas "con carácter". Sus degradados estaban a 1,05:1 de una tarjeta
 * normal, o sea que eran indistinguibles: seis tarjetas especiales que no se
 * distinguían de las corrientes. Ahora llevan fondo teñido de verdad, una franja
 * de color en el canto y sombra de nivel 2. */
.card.acento, .recuerdo, .aviso-monte, .checklist-abierta, .checklist-hecha, .card.destacada {
  position: relative; overflow: hidden; box-shadow: var(--sombra-2);
}
.card.acento::before, .recuerdo::before, .aviso-monte::before,
.checklist-abierta::before, .checklist-hecha::before, .card.destacada::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--franja-color, var(--acento));
}
.card.acento    { background: var(--acento-fondo); --franja-color: var(--acento); }
.recuerdo       { background: var(--ojo-fondo);    --franja-color: var(--ojo); }
.aviso-monte    { background: var(--ojo-fondo);    --franja-color: var(--ojo); }
.aviso-monte h2 { color: var(--ojo); }
.checklist-abierta { background: var(--ojo-fondo); --franja-color: var(--ojo); }
.checklist-hecha   { background: var(--si-fondo);  --franja-color: var(--si); }
.card.destacada { background: var(--acento-fondo); --franja-color: var(--acento); }

.punto {
  display: inline-block; width: .7rem; height: .7rem; border-radius: 50%; flex: none;
  /* Un anillo del color de la superficie: sobre un fondo teñido, un punto de
   * color sin separación se funde con el fondo. */
  box-shadow: 0 0 0 1.5px var(--tarjeta);
}
.punto.grande { width: 1.2rem; height: 1.2rem; vertical-align: -3px; }
.etiqueta {
  display: inline-block;
  font-size: var(--t5); text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
  padding: .1rem .4rem; border-radius: 4px;
  background: var(--lienzo-2); color: var(--tinta-2); border: 1px solid var(--borde);
}
/* La inicial de la persona: codificación SECUNDARIA obligatoria. Siempre sobre
 * el velo, jamás sobre el color. */
.inicial {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.55em; height: 1.55em; border-radius: 50%;
  font-size: var(--t5); font-weight: 700; font-family: var(--sans);
  color: var(--tinta); background: var(--velo);
  box-shadow: 0 0 0 2px var(--color, var(--tinta-3)) inset;
}

/* --- listas --- */
.lista-estancias, .lista-simple, .lista-registro, .barras, .lista-elegir, .marcas,
.lista-compra, .agenda-lista { list-style: none; padding: 0; margin: 0; }
.lista-estancias li, .lista-simple li {
  display: flex; align-items: center; gap: .7rem;
  padding: .6rem 0; border-top: 1px solid var(--borde);
}
.lista-estancias li:first-child, .lista-simple li:first-child { border-top: 0; }
.lista-estancias li > div, .lista-simple li > div { flex: 1; min-width: 0; }
.lista-estancias b, .lista-simple b { display: block; }
.lista-estancias .sub, .lista-simple .sub { display: block; font-size: var(--t5); margin: 0; }
/* Este dato es un DATO (cuándo llega alguien), no adorno: va en tinta-2. */
.cuando { font-size: var(--t5); color: var(--tinta-2); text-align: right; white-space: nowrap; }
.lista-estancias li.mia b { color: var(--acento); }

/* --- barras de reparto: el nombre y la cifra en tinta, nunca sobre el color --- */
.barras li {
  display: grid;
  /* minmax y no 4,5rem clavado: con el texto al 132% el nombre "Guillermo" se
   * salía de la columna y pisaba la barra. */
  grid-template-columns: minmax(4.5rem, max-content) 1fr minmax(3.2rem, max-content);
  gap: .6rem; align-items: center; padding: .35rem 0;
}
.barra-nombre { font-size: var(--t4); }
.barra-pista {
  position: relative; height: .6rem; border-radius: 999px; overflow: hidden;
  /* El "vacío medible": antes estaba a 1,21:1 y una barra al 8% parecía un muñón
   * sin escala. Ahora el carril se ve y lleva marcas al 25/50/75%. */
  background: var(--andamio);
  /* El marco va a --borde-2 entero (3,9:1 en claro, 3,7:1 en oscuro): es el
   * contorno de un objeto gráfico y tiene que verse, que es justo lo que hace
   * medible una barra al 8%. */
  box-shadow: inset 0 0 0 1px var(--borde-2);
}
.barra-pista::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(to right,
    transparent 0 calc(25% - 1px), var(--borde-2) calc(25% - 1px) 25%);
}
.barra-relleno { position: relative; display: block; height: 100%; border-radius: 999px; }
.barra-cifra { font-size: var(--t4); text-align: right; font-variant-numeric: tabular-nums; }
.barra-cifra .sub { font-size: var(--t5); margin: 0; display: inline; }

/* --- mapa de calor del año ---
 * Rejilla de 31 columnas FIJAS. Antes .heat-celdas era un flex con flex:1, así
 * que febrero tenía celdas más anchas que enero y las doce filas no se alineaban:
 * el año no se podía leer en vertical, que es justo para lo que sirve. */
.heat { display: flex; flex-direction: column; gap: 3px; margin: .6rem 0 1rem; }
.heat-fila {
  display: grid; grid-template-columns: 2.4rem 1fr; align-items: center; gap: .45rem;
  width: 100%; min-height: 44px;           /* objetivo táctil: la fila es el botón */
  padding: 0; border: 0; background: transparent; cursor: pointer;
  font: inherit; text-align: left; color: inherit;
  border-radius: 6px;
}
.heat-fila[aria-expanded="true"] { background: var(--lienzo-2); }
.heat-mes { font-size: var(--t5); color: var(--tinta-2); text-transform: capitalize; }
.heat-celdas { display: grid; grid-template-columns: repeat(31, 1fr); gap: 1px; }
.heat-celda {
  height: 14px; border-radius: 2px;
  background: var(--andamio);
  box-shadow: inset 0 0 0 1px var(--borde-2);
}
/* Fin de semana marcado: sin esto, "cada cuadrito es una noche" no se sabe leer. */
.heat-celda.finde { background: color-mix(in srgb, var(--andamio) 60%, var(--borde-2)); }
/* Los días que ese mes no tiene: andamio sin marco, para que la rejilla se vea
 * completa y febrero no parezca recortado. */
.heat-celda.nohay { background: transparent; box-shadow: none; }
.heat-celda.con { box-shadow: none; }
.heat-detalle {
  margin: .2rem 0 .6rem 2.85rem; padding-left: .6rem;
  border-left: 2px solid var(--borde); font-size: var(--t5); color: var(--tinta-2);
}
.heat-leyenda {
  display: flex; flex-wrap: wrap; gap: .35rem .8rem; margin: .2rem 0 0;
  padding: 0; list-style: none; font-size: var(--t5);
}
.heat-leyenda li { display: flex; align-items: center; gap: .35rem; color: var(--tinta-2); }

/* ============================================================== calendario ==
 * PASTILLAS CONTINUAS. Antes cada celda llevaba su propio fondo y un `gap: 2px`
 * lo partía todo: una estancia de seis noches se veía como seis cuadrados
 * separados, o sea confeti en vez de estancias. Ahora el color lo pinta un
 * pseudo-elemento que se estira por debajo del número, el hueco entre columnas
 * es cero y solo se redondean los extremos de verdad.
 */
.cal-cabecera-mes {
  position: sticky; top: var(--alto-cabecera); z-index: 15;
  margin: 0 -4px .5rem; padding: .45rem 4px .4rem;
  background: color-mix(in srgb, var(--lienzo) 94%, transparent);
  backdrop-filter: blur(8px);
  font-family: var(--serif); font-size: var(--t2); font-weight: 600;
}
.cal-mes {
  margin-bottom: 20px;
  /* los meses fuera de pantalla no se pintan: un año son ~400 celdas. La
   * estimación era 320 px cuando un mes mide ~460, y el scroll saltaba cada vez
   * que un mes entraba en pantalla y se medía de verdad. */
  content-visibility: auto; contain-intrinsic-size: auto 460px;
}
.cal-rejilla {
  display: grid; grid-template-columns: repeat(7, 1fr);
  row-gap: 5px; column-gap: 0;
}
/* Aquí vivía `.cal-barra-dias { margin-inline: -2px }`, que compensaba a mano
 * que la cabecera metiera 16 px de relleno y main 14. Ya no hace falta: los dos
 * salen de --respiro-izq/--respiro-der y de --ancho-lectura, así que las siete
 * columnas caen solas en el mismo sitio a cualquier anchura. */

/* En pantallas estrechas las dos se van a sangre, juntas o ninguna. En un
 * iPhone SE no es estética: con los 14 px de `main` quedan 292 px de ancho útil
 * y siete celdas de 44 (el objetivo táctil que fija la fase C) suman 308, así
 * que se salían tres días por la derecha, recortados y sin poder tocarlos. A
 * sangre caben siete de 45,7 y no hay que elegir entre una cosa y la otra. */
@media (max-width: 400px) {
  /* Los dos negativos son EL MISMO, y ahora se ve: antes uno decía -16 y el otro
   * -14 porque cada uno cancelaba el relleno de su contenedor. */
  .cal-barra-dias, .cal-rejilla {
    margin-inline: calc(-1 * var(--respiro-izq)) calc(-1 * var(--respiro-der));
  }
  /* Yendo a sangre, la primera y la última columna tocan el canto de la
   * pantalla. La TARJETA de un día libre se separa un poco más para que no
   * parezca cortada; la pastilla de una estancia no lleva esto a propósito,
   * porque tiene que llegar al borde o se ve un corte a mitad de una estancia. */
  .cal-rejilla > .cal-dia:not(.ocupado):not(.dia-salida):nth-child(7n+1)::before { left: 5px; }
  .cal-rejilla > .cal-dia:not(.ocupado):not(.dia-salida):nth-child(7n)::before   { right: 5px; }
}
.cal-vacio { aspect-ratio: 1; }

.cal-dia {
  position: relative;
  aspect-ratio: 1; min-height: 44px;      /* objetivo táctil, papá también entra */
  display: flex; align-items: center; justify-content: center;
  border: 0; padding: 0; margin: 0; font: inherit; font-size: var(--t4);
  color: var(--tinta); background: transparent; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.cal-num {
  position: relative; z-index: 2;
  /* en `em` para que la pastilla del número crezca con el texto: en px, al subir
   * el tamaño de letra el número se salía de su círculo. */
  display: flex; align-items: center; justify-content: center;
  min-width: 1.7em; height: 1.7em; border-radius: 999px;
}
/* EL ORDEN DE ESTE BLOQUE ES EL CONTRATO. Todos los estados de un día pintan el
 * mismo pseudo-elemento, así que la regla que gana es la última que se declara,
 * y por eso van de menos a más específico: base, pasado, ocupado y sus variantes,
 * día de salida, y la selección al final, que siempre manda. La primera versión
 * de esto usaba :not(.ocupado):not(.dia-salida) en la regla base, que sumaba MÁS
 * especificidad que .cal-dia.elegido, así que un día elegido se seguía pintando
 * con el fondo de tarjeta y la selección no se veía. */

/* Base: el día libre. Fondo de tarjeta, para que se lea como "se puede tocar". */
.cal-dia::before {
  content: ''; position: absolute; inset: 3px 2px; z-index: 0;
  background: var(--tarjeta); border: 1px solid var(--borde); border-radius: 8px;
}
/* Fin de semana y festivo, DE LOS PRIMEROS a propósito: son la piel del día
 * libre, no un estado. Van aquí, justo detrás de la base, para que ocupado, día
 * de salida y elegido los pisen. Un festivo ocupado se tiene que seguir viendo
 * ocupado, que es el dato que importa.
 * Los colores salen de --andamio, el token del "hueco medible" que ya usa el
 * mapa de calor para marcar el finde: no se inventa ninguno, porque la paleta
 * está validada para daltonismo y un color nuevo habría que revalidarlo. Sobre
 * la tarjeta el andamio se rebaja con color-mix, y así funciona igual en claro
 * (tinta un blanco) y en oscuro (aclara un gris). */
.cal-dia.finde::before   { background: color-mix(in srgb, var(--andamio) 30%, var(--tarjeta)); }
/* El festivo pesa más que el finde porque es la excepción, no la norma. Antes
 * era solo el punto de 4 px de más abajo, que a un brazo de distancia no se ve;
 * el punto se queda como segunda codificación (el fondo solo no basta si alguien
 * mira la pantalla con el sol de cara). */
.cal-dia.festivo::before {
  background: color-mix(in srgb, var(--andamio) 62%, var(--tarjeta));
  border-color: var(--borde-2);
}

/* Los días pasados van atenuados, pero el número de un día pasado OCUPADO se
 * quedaba a 2,19:1: `.pasado` ganaba en especificidad y pintaba tinta-3 sobre el
 * velo. El velo lleva su propia tinta y manda. */
.cal-dia.pasado { color: var(--tinta-3); }
.cal-dia.pasado::before { background: transparent; border-color: transparent; opacity: .5; }
.cal-dia.pasado.ocupado .cal-num, .cal-dia.pasado.dia-salida .cal-num { color: var(--tinta); }

/* Más allá de la próxima reserva no se puede llegar: se atenúa AHORA en vez de
 * dejar que lo toques y darte un error después. */
.cal-dia.inalcanzable { opacity: .45; }

.cal-dia.hoy .cal-num { box-shadow: 0 0 0 2px var(--acento); font-weight: 700; }

/* --- ocupado: la pastilla continua --- */
.cal-dia.ocupado::before {
  inset: 3px 0; background: var(--color); border: 0; border-radius: 0;
}
.cal-dia.ocupado.inicio::before { left: 3px; border-radius: 999px 0 0 999px; }
.cal-dia.ocupado.fin::before    { right: 3px; border-radius: 0 999px 999px 0; }
.cal-dia.ocupado.inicio.fin::before { border-radius: 999px; }
/* Si al día siguiente alguien se va (media pastilla), la pastilla no se cierra:
 * si no, quedaba un corte con un hueco de 3 px en medio de una misma estancia. */
.cal-dia.ocupado.fin.pegado::before { right: 0; border-radius: 0; }
/* Fecha fija de la familia: rayado, que es la tercera codificación y se explica
 * en la leyenda. */
.cal-dia.protegido::before {
  background: repeating-linear-gradient(135deg,
    var(--color) 0 6px, color-mix(in srgb, var(--color) 62%, var(--tarjeta)) 6px 12px);
}
/* Lo tuyo: contorno de tinta. Va en el pseudo-elemento para que siga la pastilla,
 * y SOLO por los bordes de fuera. Un `inset 0 0 0 2px` en cada celda dibujaba una
 * raya vertical en cada frontera de día, así que tu propia estancia salía como una
 * rejilla negra en vez de una pastilla con contorno. El contorno marca TUS NOCHES:
 * cierra en el último día que duermes, no en la media pastilla de la mañana que
 * te vas, que ya es un día libre. */
.cal-dia.mia::before {
  box-shadow:
    inset 0 2px 0 0 var(--tinta),
    inset 0 -2px 0 0 var(--tinta),
    inset var(--mia-izq, 0) 0 0 0 var(--tinta),
    inset var(--mia-der, 0) 0 0 0 var(--tinta);
}
.cal-dia.mia.inicio::before { --mia-izq: 2px; }
.cal-dia.mia.fin::before    { --mia-der: -2px; }
/* El número, sobre un velo del color de la tarjeta. NUNCA texto sobre el color. */
.cal-dia.ocupado .cal-num, .cal-dia.dia-salida .cal-num {
  background: var(--velo); color: var(--tinta);
}

/* Día de salida: media pastilla, porque la casa está libre desde esa mañana. */
.cal-dia.dia-salida::before {
  inset: 3px 0; border: 0; border-radius: 0;
  background: linear-gradient(to right, var(--color) 0 48%, transparent 48%);
}
.cal-dia.dia-salida.suelta::before { left: 3px; border-radius: 999px 0 0 999px; }

/* --- selección: siempre la última palabra --- */
.cal-dia.elegido::before {
  inset: 3px 0; background: var(--acento); border: 0; border-radius: 0;
}
.cal-dia.elegido .cal-num { color: var(--acento-tinta); background: transparent; }
.cal-dia.elegido-inicio::before { left: 3px; border-radius: 999px 0 0 999px; }
.cal-dia.elegido-salida::before {
  right: 3px; border-radius: 0 999px 999px 0;
  background: linear-gradient(to right, var(--acento) 0 48%, transparent 48%);
}
.cal-dia.elegido-inicio.elegido-salida::before { border-radius: 999px; }

/* Los días que chocan con lo que acabas de intentar reservar. El 409 del backend
 * trae el día y de quién es; marcarlos dura hasta el toque siguiente, mucho más
 * útil que un aviso que se va en cuatro segundos. */
.cal-dia.choque::after {
  content: ''; position: absolute; inset: 1px 0; z-index: 3;
  border: 2px dashed var(--no); border-radius: 6px;
  animation: latido 1.1s ease-in-out 3;
}
@media (prefers-reduced-motion: reduce) { .cal-dia.choque::after { animation: none; } }
@keyframes latido { 50% { opacity: .35; } }

/* Segunda marca del festivo: un punto bajo el número.
 * OJO, este comentario decía antes que "un festivo no puede pintar un fondo,
 * porque el color ya está ocupado por las personas". Ya no es verdad: el fondo
 * se pinta arriba, con un gris del andamio y no con un color de persona, y va
 * ANTES de `ocupado` en el bloque del contrato, así que un festivo ocupado se
 * sigue viendo ocupado. El punto se queda como segunda codificación, que es lo
 * que sobrevive encima del color de una estancia. */
.cal-dia.festivo .cal-num::after {
  content: ''; position: absolute; bottom: -.15em; left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: var(--tinta-2);
}
.cal-dia.festivo.ocupado .cal-num::after { background: var(--tinta); }

.cal-leyenda { list-style: none; padding: 0; margin: .5rem 0 0; }
.cal-leyenda li {
  display: flex; align-items: center; gap: .45rem; font-size: var(--t5);
  padding: .15rem 0; color: var(--tinta-2);
}
.cal-leyenda b { color: var(--tinta); font-weight: 600; }
.cal-nadie { font-size: var(--t5); color: var(--tinta-2); margin: .4rem 0 0; }
.ancho { width: 100%; }

/* Instrucción antes del primer toque. Sin esto el calendario parece de solo
 * lectura: nadie adivina que se toca el día de llegada y luego el de salida. */
.cal-instruccion {
  display: flex; gap: .6rem; align-items: flex-start;
  margin-bottom: 12px; padding: .75rem .85rem;
  background: var(--acento-fondo); color: var(--tinta);
  border-radius: var(--radio-s); font-size: var(--t4);
  border: 1px solid color-mix(in srgb, var(--acento) 28%, transparent);
}
.cal-instruccion b { display: block; }

/* Leyenda del lenguaje visual. Había CINCO codificaciones solapadas (color,
 * contorno, rayas, media pastilla, anillo de hoy) y CERO explicación en toda la
 * app. Va plegada para no gastar pantalla, pero existe. */
.leyenda-caja { margin-bottom: 12px; }
.leyenda-caja > summary {
  cursor: pointer; list-style: none; min-height: 44px;
  display: flex; align-items: center; gap: .4rem;
  font-size: var(--t4); color: var(--tinta-2); font-weight: 600;
}
.leyenda-caja > summary::-webkit-details-marker { display: none; }
.leyenda-caja > summary::after { content: '›'; transform: rotate(90deg); color: var(--tinta-3); }
.leyenda-caja[open] > summary::after { transform: rotate(-90deg); }
.leyenda-lista { list-style: none; padding: 0; margin: .2rem 0 0; }
.leyenda-lista li {
  display: grid; grid-template-columns: 2.6rem 1fr; gap: .6rem; align-items: center;
  padding: .35rem 0; font-size: var(--t5); color: var(--tinta-2);
}
.leyenda-muestra {
  position: relative; height: 1.6rem; border-radius: 8px;
  background: var(--tarjeta); border: 1px solid var(--borde);
}
.leyenda-muestra.m-ocupado { background: var(--p1); border-color: transparent; }
.leyenda-muestra.m-mia { background: var(--p3); border: 2px solid var(--tinta); }
.leyenda-muestra.m-fija {
  border-color: transparent;
  background: repeating-linear-gradient(135deg, var(--p5) 0 6px,
    color-mix(in srgb, var(--p5) 62%, var(--tarjeta)) 6px 12px);
}
.leyenda-muestra.m-salida {
  border-color: transparent;
  background: linear-gradient(to right, var(--p2) 0 48%, var(--tarjeta) 48%);
}
.leyenda-muestra.m-hoy { display: grid; place-items: center; }
.leyenda-muestra.m-hoy i {
  width: 1.1rem; height: 1.1rem; border-radius: 50%; box-shadow: 0 0 0 2px var(--acento);
}
/* La del finde tiene que llevar el MISMO tinte que la celda, por lo mismo que la
 * del festivo de abajo: sin esta regla la muestra caía al fondo base y se veía
 * igual que un día normal, o sea que la leyenda decía "así se ven los sábados y
 * los domingos" enseñando un cuadro en blanco. */
.leyenda-muestra.m-finde {
  background: color-mix(in srgb, var(--andamio) 30%, var(--tarjeta));
}

/* La muestra del festivo lleva el fondo de verdad, no solo el punto: si la
 * leyenda enseña una cosa y la rejilla otra, la leyenda estorba. */
.leyenda-muestra.m-festivo {
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--andamio) 62%, var(--tarjeta));
  border-color: var(--borde-2);
}
.leyenda-muestra.m-festivo i {
  width: 4px; height: 4px; border-radius: 50%; background: var(--tinta-2);
}

/* --- conmutador rejilla / agenda --- */
.conmutador-caja { display: flex; align-items: center; gap: .5rem; }
.conmutador {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--lienzo-2); border: 1px solid var(--borde); border-radius: 999px;
}
.conmutador button {
  font: inherit; font-size: var(--t5); font-weight: 600;
  /* 44 y no 38: aquí sí se puede crecer, porque el conmutador va en el cuerpo
   * de la vista y no hay ningún `top:` pegajoso colgando de su altura. */
  min-height: 44px; padding: 0 .9rem; border: 0; border-radius: 999px;
  background: transparent; color: var(--tinta-2); cursor: pointer;
}
.conmutador button[aria-pressed="true"] {
  background: var(--tarjeta); color: var(--tinta); box-shadow: var(--sombra-1);
}

/* --- agenda: la lista de estancias en orden --- */
.agenda-grupo { margin-bottom: 18px; }
.agenda-titulo {
  position: sticky; top: var(--alto-cabecera); z-index: 15;
  margin: 0 -4px .4rem; padding: .4rem 4px;
  background: color-mix(in srgb, var(--lienzo) 94%, transparent);
  backdrop-filter: blur(8px);
  font-family: var(--serif); font-size: var(--t2);
}
.agenda-lista li { margin-bottom: 8px; }
.pastilla-agenda {
  display: grid; grid-template-columns: 3.4rem 1fr auto; gap: .75rem; align-items: center;
  width: 100%; padding: .7rem .8rem; min-height: 60px;
  text-align: left; font: inherit; cursor: pointer;
  background: var(--tarjeta); border: 1px solid var(--borde);
  border-left: 5px solid var(--color, var(--borde-2));
  border-radius: var(--radio-s); color: var(--tinta);
}
.pastilla-agenda.mia { box-shadow: inset 0 0 0 2px var(--tinta); }
.pastilla-agenda.pasada { opacity: .62; }
.agenda-fecha { text-align: center; font-variant-numeric: tabular-nums; line-height: 1.15; }
.agenda-fecha b { display: block; font-size: var(--t2); font-family: var(--sans); }
.agenda-fecha span { display: block; font-size: var(--t5); color: var(--tinta-2); }
.agenda-quien { min-width: 0; }
.agenda-quien b { display: block; }
.agenda-quien span { display: block; font-size: var(--t5); color: var(--tinta-2); }
.agenda-noches { font-size: var(--t5); color: var(--tinta-2); white-space: nowrap; }
.agenda-festivos {
  margin: .1rem 0 .5rem; padding: .5rem .7rem;
  background: var(--lienzo-2); border-radius: var(--radio-s);
  font-size: var(--t5); color: var(--tinta-2);
}
.agenda-festivos b { color: var(--tinta); }

/* --- barra flotante de selección --- */
.barra-seleccion {
  position: fixed; left: 0; right: 0; z-index: 40;
  /* Pegada a la navegación, sin la rendija de 7 px de antes: las dos medidas
   * salen del ResizeObserver, no de un número a ojo. */
  bottom: var(--alto-nav);
  display: flex; align-items: center; gap: .6rem;
  padding: 12px max(14px, env(safe-area-inset-left));
  background: var(--tarjeta-2); border-top: 1px solid var(--borde);
  box-shadow: var(--sombra-3);
}
.barra-texto { flex: 1; min-width: 0; }
.barra-texto b { display: block; font-size: var(--t4); }
.barra-texto .sub { display: block; font-size: var(--t5); margin: 0; }

/* --- botones --- */
/* `display: inline-flex` no es cosmética: la mitad de estos botones son
 * `<a>` (el enlace a las carreteras, "Ver el resumen", "Ver qué falta"), y
 * `min-height` NO se aplica a un elemento inline no reemplazado. Sin esto los
 * enlaces medían 38 px reales mientras el CSS decía 44, y el dedo de papá se
 * queda igual de corto aunque la hoja de estilos prometa lo contrario. */
.btn, .btn-secundario, .btn-peligro, .btn-plano {
  display: inline-flex; align-items: center; justify-content: center;
  /* Sin esto, los que son <a> salen SUBRAYADOS y parecen un enlace en medio de
   * un texto en vez de un botón. Se veía en el hero de la portada. */
  text-decoration: none;
  font: inherit; font-size: var(--t4); font-weight: 600;
  padding: .6rem 1rem; border-radius: var(--radio-s);
  border: 1px solid transparent; cursor: pointer; min-height: 44px;
}
.btn { background: var(--acento); color: var(--acento-tinta); }
.btn.grande { width: 100%; margin-top: 1.2rem; padding: .9rem; font-size: var(--t3); }
.btn-secundario { background: var(--lienzo-2); color: var(--tinta); border-color: var(--borde); }
.btn-peligro { background: var(--no-fondo); color: var(--no); }
.btn-plano { background: transparent; color: var(--tinta-2); }
.btn-claro {                    /* también se usa como <a>: ver arriba */
  display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none;
  background: rgba(255,255,255,.16); color: #fff;
  border: 1px solid rgba(255,255,255,.5);
  font: inherit; font-size: var(--t4); font-weight: 600;
  padding: .6rem 1rem; border-radius: var(--radio-s); min-height: 44px; cursor: pointer;
  backdrop-filter: blur(4px);
}
.btn-claro.primario { background: #fff; color: #14231d; border-color: #fff; }
.btn:disabled, .btn-secundario:disabled, .btn-peligro:disabled,
.btn-plano:disabled, .btn-claro:disabled { opacity: .55; cursor: default; }
/* RESPUESTA AL TOQUE. Antes solo la tenían tres botones, así que la mitad de la
 * app se tocaba y no acusaba recibo hasta que llegaba la respuesta del servidor,
 * que en el pueblo puede ser un segundo largo. Se hunde lo que se toca: celdas
 * del calendario, pastillas de la agenda, filas del mapa de calor y las
 * pestañas. `transform` y no otra cosa porque no provoca recálculo de diseño. */
@media (prefers-reduced-motion: no-preference) {
  .btn:active:not(:disabled), .btn-secundario:active, .btn-claro:active,
  .btn-peligro:active:not(:disabled), .btn-plano:active,
  .btn-hoy:active, .conmutador button:active, .tamanos button:active,
  .pastilla-agenda:active, .heat-fila:active, .nav-item:active,
  .fila-titular:active, .lista-elegir button:active {
    transform: scale(.985);
  }
  /* En el calendario se hunde EL NÚMERO, no la celda. Escalar el ::before de la
   * celda parece lo natural, pero ese pseudo-elemento es la pastilla continua de
   * una estancia: encogerlo abriría un hueco a mitad de una reserva de seis
   * noches, o sea que el toque rompería el dibujo. El número lo lleva .cal-num,
   * que es siempre suyo y nunca se comparte con el día de al lado. */
  .cal-dia .cal-num { transition: transform .09s ease-out; }
  .cal-dia:active .cal-num { transform: scale(.88); }
}
.fila-botones { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }

/* --- navegación inferior: CINCO pestañas --- */
.bottom-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: grid; grid-template-columns: repeat(5, 1fr);
  padding-bottom: env(safe-area-inset-bottom);
  background: color-mix(in srgb, var(--lienzo) 94%, transparent);
  backdrop-filter: blur(12px); border-top: 1px solid var(--borde);
}
.nav-item {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 0 6px; min-height: 48px; text-decoration: none;
  color: var(--tinta-2); font-size: var(--t5);
}
.nav-item span { font-size: var(--t5); }
.nav-item svg { width: 22px; height: 22px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.nav-item.activo { color: var(--acento); font-weight: 600; }
/* La pestaña activa lleva además una barra arriba: el color solo no basta. */
.nav-item.activo::before {
  content: ''; position: absolute; margin-top: -8px;
  width: 26px; height: 3px; border-radius: 0 0 3px 3px; background: var(--acento);
}
.nav-item { position: relative; }

/* --- hoja inferior --- */
.hoja { position: fixed; inset: 0; z-index: 60; }
.hoja-fondo { position: absolute; inset: 0; background: rgba(0,0,0,.5); }
.hoja-panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  /* El arrastre lo escribe el JS en esta variable y NO en `transform`: a partir
     de 640 px el centrado horizontal es un transform, y sustituirlo entero
     mandaba la hoja media anchura a la izquierda mientras se arrastraba (el
     iPad de la casa mide 768 px en vertical y es táctil, así que le pasaba). */
  --arrastre: 0px;
  transform: translateY(var(--arrastre));
  /* dvh y no vh: con vh, en Safari la barra de direcciones se cuenta como
   * espacio disponible y el asa se quedaba fuera de la zona visible. */
  max-height: 88dvh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--tarjeta); border-radius: var(--radio-l) var(--radio-l) 0 0;
  padding: 0 18px calc(24px + env(safe-area-inset-bottom));
  box-shadow: var(--sombra-3);
}
@supports not (max-height: 1dvh) { .hoja-panel { max-height: 88vh; } }
@media (min-width: 640px) {
  .hoja-panel { left: 50%; right: auto;
    transform: translateX(-50%) translateY(var(--arrastre)); width: 34rem;
    border-radius: var(--radio-l); bottom: 3vh; }
}
@media (prefers-reduced-motion: no-preference) {
  .hoja-panel { animation: sube .26s cubic-bezier(.22,.61,.36,1) both; }
  @keyframes sube { from { transform: translateY(18px); opacity: .6; } }
  @media (min-width: 640px) {
    @keyframes sube { from { transform: translateX(-50%) translateY(18px); opacity: .6; } }
  }
}
/* Zona de agarre: el asa mide 42x4 px, que como objetivo táctil es una broma.
 * El área que responde al dedo y al arrastre es esta franja de 44 px de alto;
 * el asa sigue midiendo lo mismo a la vista. */
.hoja-agarre {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  height: 44px; margin: 0 -18px; background: var(--tarjeta);
  border-radius: var(--radio-l) var(--radio-l) 0 0;
  touch-action: none;
}
.hoja-asa {
  display: block; width: 42px; height: 5px; padding: 0;
  border: 0; border-radius: 999px; background: var(--borde-2); cursor: grab;
}
.hoja-asa::before {           /* área táctil ampliada sin cambiar lo que se ve */
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 44px;
}
.hoja-cabecera { display: flex; align-items: flex-start; gap: .7rem; }
.hoja-cabecera h2 { margin: 0; }
.hoja-acciones { display: flex; flex-direction: column; gap: .5rem; margin-top: 1.2rem; }
.hoja-acciones.fila { flex-direction: row; justify-content: flex-end; margin-top: .6rem; }
.nota-info {
  background: var(--acento-fondo); color: var(--tinta); font-size: var(--t4);
  padding: .6rem .75rem; border-radius: var(--radio-s); margin: .9rem 0 0;
  border: 1px solid color-mix(in srgb, var(--acento) 25%, transparent);
}
.campo { display: block; margin-top: 1rem; }
.campo span { display: block; font-size: var(--t4); color: var(--tinta-2); margin-bottom: .3rem; }
.campo input, .campo textarea {
  width: 100%; padding: .7rem .75rem; font: inherit; font-size: var(--t3);
  color: var(--tinta); background: var(--lienzo-2);
  border: 1px solid var(--borde-2); border-radius: var(--radio-s);
  min-height: 44px;
}
.campo textarea { resize: vertical; }

/* "A nombre de": UNA línea con valor por defecto, no un formulario desplegable.
 * El 95% de las reservas son para uno mismo y no deben pagar el peaje. */
.fila-titular {
  display: flex; align-items: center; gap: .6rem; width: 100%;
  margin-top: 1.1rem; padding: .8rem .75rem; min-height: 48px;
  font: inherit; text-align: left; cursor: pointer;
  background: var(--lienzo-2); border: 1px solid var(--borde);
  border-radius: var(--radio-s); color: var(--tinta-2);
}
.fila-titular b { flex: 1; text-align: right; color: var(--tinta); }
.chevron { color: var(--tinta-2); font-size: var(--t2); }

.lista-elegir li { border-top: 1px solid var(--borde); }
.lista-elegir li:first-child { border-top: 0; }
.lista-elegir button {
  display: flex; align-items: center; gap: .6rem; width: 100%;
  padding: .85rem .2rem; min-height: 48px;
  font: inherit; font-size: var(--t3); text-align: left; color: var(--tinta);
  background: transparent; border: 0; cursor: pointer;
}

.lista-registro li {
  display: grid; grid-template-columns: 5.5rem 1fr; gap: .5rem;
  padding: .45rem 0; border-top: 1px solid var(--borde); font-size: var(--t4);
}
.lista-registro li:first-child { border-top: 0; }
.reg-fecha { color: var(--tinta-2); font-variant-numeric: tabular-nums; }

/* --- avisos --- */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%) translateY(20px);
  bottom: calc(var(--alto-nav) + 18px); z-index: 80;
  max-width: min(92vw, 30rem);
  padding: .7rem 1rem; border-radius: 999px;
  background: var(--tinta); color: var(--lienzo); font-size: var(--t4);
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
  box-shadow: var(--sombra-2);
}
.toast.visible { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.mal { background: #7c1f1b; color: #fff; }
.toast.bien { background: #14432e; color: #fff; }

/* BLOQUEO REAL del scroll de fondo. `overflow: hidden` en body NO funciona en
 * iOS: Safari sigue desplazando el documento y al cerrar la hoja aparecías en
 * otro sitio. Hay que fijar la posición y devolver el scroll a mano, que es lo
 * que hace js/nucleo.js con el `top` en línea. */
body.con-hoja, body.con-visor {
  position: fixed; left: 0; right: 0; width: 100%; overflow: hidden;
}

/* --- visor de foto a pantalla completa ---
 * Antes la foto grande se abría con window.open: en la PWA instalada eso salta a
 * Safari, que tiene OTRO almacén de cookies, así que la sesión no viajaba y la
 * foto contestaba 401. */
.visor {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .8rem; padding: env(safe-area-inset-top) 12px env(safe-area-inset-bottom);
  background: rgba(6,8,11,.96);
}
.visor img { max-width: 100%; max-height: 82vh; object-fit: contain; border-radius: 6px; }
.visor-pie { margin: 0; color: #e8ecef; font-size: var(--t4); text-align: center; }
.visor-cerrar {
  position: absolute; top: calc(env(safe-area-inset-top) + 8px); right: 12px;
  width: 44px; height: 44px; border-radius: 50%; border: 0; cursor: pointer;
  font-size: var(--t3); color: #fff; background: rgba(255,255,255,.18);
}

/* ================================================================== ratón ==
 * No había NI UN :hover en toda la hoja, y sí diecisiete `cursor: pointer`: el
 * puntero cambiaba de forma y luego no pasaba nada. En un Mac eso es lo que
 * delata que estás mirando una app de móvil estirada.
 *
 * Todo dentro de @media (hover: hover): sin esa valla, iOS aplica el :hover al
 * tocar y lo DEJA PUESTO hasta que tocas otra cosa, así que quedaría un día del
 * calendario resaltado a lo tonto después de cada toque.
 *
 * Nada de esto sustituye a :focus-visible, que sigue siendo el anillo doble de
 * más arriba. Son dos cosas distintas: el foco dice "estoy aquí", el hover dice
 * "esto se puede tocar".
 */
@media (hover: hover) and (pointer: fine) {
  .btn:hover:not(:disabled) { background: color-mix(in srgb, var(--acento) 86%, var(--tinta)); }
  .btn-secundario:hover:not(:disabled) { background: var(--lienzo); border-color: var(--borde-2); }
  /* El de peligro NO cambia de fondo: teñirlo hacia --no aunque sea un 20% baja
   * el contraste de su propio texto de 4,94:1 a 3,74:1, o sea que "Salir"
   * dejaría de cumplir AA justo al apuntarlo. Se marca con un aro por dentro,
   * que no toca ningún color. */
  .btn-peligro:hover:not(:disabled) { box-shadow: inset 0 0 0 1.5px var(--no); }
  .btn-plano:hover:not(:disabled) { background: var(--lienzo-2); color: var(--tinta); }
  /* El botón claro vive sobre la escena del hero, y ahí el contraste no sale de
   * la paleta: sale del velo, que es lo único que separa el texto blanco de un
   * valle nevado a mediodía. Subir el relleno del cristal se come ese margen sin
   * que nada lo mida, así que aquí solo se enciende el borde. */
  .btn-claro:hover:not(:disabled) { border-color: #fff; }
  /* El primario sí es un rectángulo blanco opaco con tinta oscura encima: ahí el
   * fondo lo pone él y bajarlo un punto no le quita contraste a nadie. */
  .btn-claro.primario:hover:not(:disabled) { background: #eef2f0; }
  .btn-hoy:hover { background: color-mix(in srgb, var(--acento-fondo) 78%, var(--acento)); }

  /* El día libre se levanta: borde de acento y fondo de tarjeta pura. Solo el
   * borde, para no pisar el color de nadie ni el fondo de finde o festivo. */
  .cal-dia:hover:not(.inalcanzable)::before { border-color: var(--acento); }
  /* Los que llevan pastilla no tienen borde que iluminar, así que se marca el
   * velo del número, que es lo único suyo. `:not(.hoy)` porque el día de hoy ya
   * usa ese mismo aro para decir que es hoy, y pisárselo al pasar el ratón
   * borraría el único sitio donde se ve dónde estás. */
  .cal-dia.ocupado:hover:not(.hoy) .cal-num,
  .cal-dia.dia-salida:hover:not(.hoy) .cal-num {
    box-shadow: 0 0 0 2px var(--tinta-2);
  }

  .nav-item:hover { color: var(--tinta); background: var(--lienzo-2); }
  .nav-item.activo:hover { color: var(--acento); }

  .pastilla-agenda:hover { background: var(--tarjeta-2); border-color: var(--borde-2); box-shadow: var(--sombra-1); }
  .heat-fila:hover { background: var(--lienzo-2); }
  .conmutador button:hover:not([aria-pressed="true"]) { color: var(--tinta); }
  .tamanos button:hover:not([aria-pressed="true"]) { border-color: var(--borde-2); background: var(--lienzo); }
  .leyenda-caja > summary:hover { color: var(--tinta); }
  .fila-titular:hover { border-color: var(--borde-2); background: var(--lienzo); }
  .lista-elegir button:hover { background: var(--lienzo-2); }
  .marcas label:hover, .lista-compra label:hover { color: var(--acento); }
  .entrada .editar:hover { background: var(--lienzo-2); color: var(--tinta); }
  .compra-quitar:hover { background: var(--no-fondo); color: var(--no); }
  .subir:hover { color: var(--acento); }
  .hoja-asa:hover { background: var(--tinta-3); }
  .visor-cerrar:hover { background: rgba(255,255,255,.32); }
  /* Zoom en la miniatura, no en la caja: la caja tiene `overflow: hidden`, así
   * que la foto crece por dentro y el hueco de la rejilla no se mueve. */
  .fotos .foto-boton:hover img, .resumen-fotos button:hover img { transform: scale(1.04); }
  .fotos img, .resumen-fotos img { transition: transform .18s ease-out; }
  @media (prefers-reduced-motion: reduce) {
    .fotos .foto-boton:hover img, .resumen-fotos button:hover img { transform: none; }
  }
}

/* --- escritorio ---
 * A 1280 px la app era una columna de móvil de 736 px flotando en el centro con
 * 544 px de lienzo vacío a los lados (el 42% de la pantalla) y dos barras
 * cruzando de canto a canto. Lo que sigue lo convierte en una app de escritorio:
 * la columna se ensancha, el contenido se reparte en dos, la barra de abajo se
 * pone de pie a la izquierda y las celdas del calendario dejan de ser cuadrados
 * de 101 px.
 */
@media (min-width: 780px) {
  /* LAS DOS a la vez, del mismo token. Esto es el arreglo del desalineado. */
  main, .superior-caja { max-width: var(--ancho-lectura); margin-inline: auto; }
  .bottom-nav { grid-template-columns: repeat(5, 8rem); justify-content: center; }

  /* CELDAS DEL CALENDARIO: techo de altura.
   * `aspect-ratio: 1` sobre columnas de 101 px daba celdas de 101x101 y un mes
   * de 631 px solo de rejilla: en un Mac entraba mes y pico por pantalla. El
   * `min-height: 52px` que había aquí no hacía NADA, porque con aspect-ratio la
   * altura la manda el ancho. Se apaga el aspect-ratio y la altura pasa a ser
   * una medida de texto, que además crece si alguien pone la letra en "enorme".
   * .cal-vacio va en el mismo saco: son los huecos del principio de mes, llevan
   * el mismo aspect-ratio y sin esto la primera semana se quedaba con la altura
   * vieja y descuadraba la fila entera. No necesitan altura propia: son
   * elementos de rejilla y la fila ya se la da su día vecino.
   * El corte va en 780 y no más arriba a propósito: 780 es exactamente donde
   * main se capa y aparecen las columnas anchas, o sea donde nace el problema. */
  .cal-dia, .cal-vacio { aspect-ratio: auto; }
  .cal-dia { min-height: calc(3.75rem * var(--escala)); }
  /* La estimación de 460 px estaba calibrada para el móvil. Con la celda
   * acotada un mes mide ~435, y como el valor va con `auto` el navegador se
   * queda con la medida real en cuanto pinta el mes una vez. */
  .cal-mes { contain-intrinsic-size: auto 440px; }

  /* EL HERO. Medía 736x304 con el texto apelotonado abajo a la izquierda y dos
   * tercios de escena vacíos a la derecha. Se le da altura (entra más valle: el
   * SVG es 2:1 y se recorta por arriba y por abajo) y aire, y se le pone medida
   * de lectura al bloque de texto, que si no el titular tiraba una línea de 680
   * px de largo. El relleno de arriba SUBE, no baja: las paradas del velo se
   * cuentan desde el borde de arriba del bloque, así que el texto cae más abajo
   * en la rampa, o sea sobre MÁS velo. El gate de contraste no puede empeorar. */
  .hero { min-height: 21rem; }
  .hero-texto { padding: 118px 30px 30px; }
  .hero-texto > *:not(.hero-acciones) { max-width: 34rem; }
}

/* --- ajustes --- */
.pasos { padding-left: 1.15rem; margin: .8rem 0 0; color: var(--tinta-2); font-size: var(--t4); }
.pasos li { margin-bottom: .45rem; }
.pasos b { color: var(--tinta); }
.campo-copiar {
  width: 100%; margin-top: .5rem; padding: .6rem .7rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t5);
  color: var(--tinta); background: var(--lienzo-2);
  border: 1px solid var(--borde-2); border-radius: var(--radio-s);
  -webkit-user-select: all; user-select: all;
}
.tamanos { display: flex; gap: .5rem; margin-top: .6rem; }
.tamanos button {
  flex: 1; font: inherit; font-weight: 600; min-height: 48px;
  border: 1px solid var(--borde); border-radius: var(--radio-s);
  background: var(--lienzo-2); color: var(--tinta); cursor: pointer;
}
.tamanos button[aria-pressed="true"] {
  background: var(--acento); color: var(--acento-tinta); border-color: transparent;
}
.tamanos button:nth-child(1) { font-size: .9rem; }
.tamanos button:nth-child(2) { font-size: 1.05rem; }
.tamanos button:nth-child(3) { font-size: 1.2rem; }

/* --- parte de la montaña --- */
.cifras { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem; margin: .3rem 0 .2rem; }
.cifras > div { display: flex; flex-direction: column; gap: .1rem; }
/* la cifra protagonista SIEMPRE en sans, nunca en la serif de los titulares */
.cifra { font-family: var(--sans); font-size: var(--t-cifra2); font-weight: 650;
         font-variant-numeric: tabular-nums; line-height: 1.1; }
.cifra small { font-size: .58em; font-weight: 500; color: var(--tinta-2); margin-left: .1em; }
.cifra.sindato { color: var(--tinta-3); font-size: var(--t3); font-weight: 500; }
.cifras .sub { font-size: var(--t5); margin: 0; }

.parte { list-style: none; padding: 0; margin: 0; }
.parte li {
  display: grid; grid-template-columns: 3.6rem 1fr 2.8rem 4.4rem;
  gap: .4rem; align-items: baseline;
  padding: .5rem 0; border-top: 1px solid var(--borde); font-size: var(--t4);
}
.parte li:first-child { border-top: 0; }
.parte-dia { color: var(--tinta-2); text-transform: capitalize; }
.parte-cielo { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.parte-cielo b { color: var(--p1); }
.parte-lluvia, .parte-temp { text-align: right; font-variant-numeric: tabular-nums;
  color: var(--tinta-2); }
.parte-temp b { color: var(--tinta); }

/* --- libro de la casa --- */
.entrada { padding: .8rem 0; border-top: 1px solid var(--borde); }
.entrada:first-of-type { border-top: 0; padding-top: 0; }
.entrada h3 {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  font-size: var(--t3); margin: 0 0 .3em;
}
.entrada p { margin: 0; color: var(--tinta-2); font-size: var(--t4);
  -webkit-user-select: text; user-select: text; }
.entrada.vacia p { color: var(--tinta-3); font-style: italic; }
/* Era 25 px de alto con min-height:0 explícito. Ahora 44, con el tamaño visual
 * pequeño y el área táctil ampliada por pseudo-elemento. */
.entrada .editar {
  position: relative; font-size: var(--t5); padding: .2rem .5rem;
  min-height: 0; flex: none;
}
.entrada .editar::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.entrada textarea {
  width: 100%; padding: .6rem .7rem; font: inherit; font-size: var(--t4);
  color: var(--tinta); background: var(--lienzo-2);
  border: 1px solid var(--borde-2); border-radius: var(--radio-s); resize: vertical;
}

.marcas li { border-top: 1px solid var(--borde); }
.marcas li:first-child { border-top: 0; }
.marcas label {
  display: flex; align-items: center; gap: .7rem;
  padding: .7rem 0; min-height: 48px; cursor: pointer; font-size: var(--t4);
}
.marcas input { width: 1.4rem; height: 1.4rem; accent-color: var(--si); flex: none; }
.marcas input:checked + span { color: var(--tinta-3); text-decoration: line-through; }
.marcas li.guardando { opacity: .6; }

/* --- lista de la compra --- */
.compra-alta { display: flex; gap: .5rem; margin: .2rem 0 .8rem; }
.compra-alta input {
  flex: 1; min-width: 0; padding: .7rem .75rem; font: inherit; font-size: var(--t3);
  color: var(--tinta); background: var(--lienzo-2); min-height: 44px;
  border: 1px solid var(--borde-2); border-radius: var(--radio-s);
}
.lista-compra li {
  display: flex; align-items: center; gap: .6rem;
  padding: .3rem 0; border-top: 1px solid var(--borde);
}
.lista-compra li:first-child { border-top: 0; }
.lista-compra label {
  flex: 1; display: flex; align-items: center; gap: .7rem;
  min-height: 48px; cursor: pointer; font-size: var(--t4); min-width: 0;
}
.lista-compra input[type=checkbox] {
  width: 1.4rem; height: 1.4rem; accent-color: var(--si); flex: none;
}
.compra-texto { min-width: 0; }
.compra-texto b { display: block; font-weight: 500; }
.compra-texto span { display: block; font-size: var(--t5); color: var(--tinta-2); }
.lista-compra li.comprado .compra-texto b { color: var(--tinta-3); text-decoration: line-through; }
.compra-quitar {
  position: relative; flex: none; width: 44px; height: 44px;
  border: 0; border-radius: 50%; background: transparent; color: var(--tinta-2);
  font-size: var(--t3); cursor: pointer;
}

/* --- fichas de teléfono y de sitio ---
 *
 * FICHAS y no un párrafo con el número dentro. La razón no es estética: un
 * número escrito en medio de un texto hay que seleccionarlo, copiarlo y pegarlo
 * en el teclado del teléfono, y con setenta años eso decide si se usa la app.
 * Aquí el objetivo táctil es la FILA COMPLETA y lleva `tel:` detrás, así que
 * llamar es un toque. De ahí los 56 px de alto: no es aire, es la diana. */
.fichas { list-style: none; padding: 0; margin: .2rem 0 .9rem; }
.fichas li {
  display: flex; align-items: center; gap: .3rem;
  border-top: 1px solid var(--borde);
}
.fichas li:first-child { border-top: 0; }
.ficha-enlace {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: .7rem;
  min-height: 56px; padding: .45rem 0;
  color: var(--tinta); text-decoration: none; font-size: var(--t4);
}
.ficha-icono {
  flex: none; width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 50%; background: var(--acento-fondo); color: var(--acento);
}
.ficha-icono svg { width: 18px; height: 18px; fill: currentColor; }
.ficha-texto { min-width: 0; }
.ficha-texto b { display: block; font-weight: 600; }
/* El número, en sans y con cifras de ancho fijo: es un DATO que se lee de un
 * vistazo, no prosa (misma regla que las cifras del resto de la app). */
.ficha-valor {
  display: block; font-family: var(--sans); font-variant-numeric: tabular-nums;
  color: var(--tinta-2); font-size: var(--t4);
}
.ficha-nota, .ficha-roto {
  display: block; font-size: var(--t5); color: var(--tinta-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ficha-roto { color: var(--no); white-space: normal; }
/* Ficha sin enlace utilizable: se ve que es texto y no un botón. */
.ficha-enlace.muerta { color: var(--tinta-2); }
.ficha-enlace.muerta .ficha-icono { background: var(--lienzo-2); color: var(--tinta-3); }
/* Mismo truco que "Editar" en las entradas del libro: se ve de 22 px y el dedo
 * tiene 44 por el pseudo-elemento. El arnés de navegador lo mide leyendo el CSS
 * calculado del ::after, así que se mantiene solo. */
.ficha-editar {
  position: relative; flex: none;
  padding: .2rem .5rem; min-height: 0; font-size: var(--t5);
}
.ficha-editar::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.ficha-nada { font-size: var(--t4); margin: .2rem 0 .9rem; }
/* El esqueleto con la FORMA de una ficha, no con la palabra "cargando". */
.hueso-ficha { height: 34px; margin: .6rem 0; border-radius: 999px; }

/* --- fotos --- */
.fotos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 1rem; }
.fotos figure { position: relative; margin: 0; aspect-ratio: 1; }
.fotos .foto-boton {
  display: block; width: 100%; height: 100%; padding: 0; border: 0; cursor: zoom-in;
  background: var(--lienzo-2); border-radius: var(--radio-s); overflow: hidden;
}
.fotos img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Era de 26 px. Ahora 44 reales, con el círculo visible más pequeño. */
.fotos .quitar {
  position: absolute; top: -6px; right: -6px;
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; background: transparent; cursor: pointer; color: #fff;
  font-size: var(--t4); line-height: 1; padding: 0;
}
.fotos .quitar > span {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 999px; background: rgba(0,0,0,.62);
  box-shadow: 0 0 0 1px rgba(255,255,255,.45);
}
.fotos .quitar.confirmando > span { width: auto; padding: 0 .5rem; background: var(--no); }
.fotos .sub { grid-column: 1 / -1; margin: 0; font-size: var(--t4); }
.subir { display: block; text-align: center; margin-top: .8rem; cursor: pointer; }

/* ============================================================== esqueletos ==
 * Con la FORMA real. El estado de carga era una línea de texto y el contenido
 * de Montaña son ~1.400 px: al llegar los datos la página daba un salto brutal
 * y quien estuviera leyendo perdía el sitio.
 */
.hueso {
  background: var(--andamio); border-radius: 6px;
  animation: pulso 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .hueso { animation: none; } }
@keyframes pulso { 50% { opacity: .5; } }
.hueso-linea { height: 1em; margin: .45rem 0; }
.hueso-titulo { height: 1.4em; width: 45%; margin: 0 0 .8rem; }
.hueso-cifra { height: 2.2rem; width: 3.4rem; }
.hueso-hero { min-height: 17rem; border-radius: var(--radio); }
@media (min-width: 780px) { .hueso-hero { min-height: 19rem; } }
.hueso-fila { display: grid; grid-template-columns: 3.6rem 1fr 2.8rem 4.4rem;
  gap: .4rem; padding: .55rem 0; border-top: 1px solid var(--borde); }
.hueso-fila > span { height: 1em; }

/* Estado vacío decente. Libro podía quedarse COMPLETAMENTE en blanco si no
 * había estancia y ninguna sección tenía entradas. */
.vacio { text-align: center; padding: 1.4rem .6rem; }
.vacio svg { width: 44px; height: 44px; color: var(--tinta-3); fill: none;
  stroke: currentColor; stroke-width: 1.4; margin-bottom: .5rem; }
.vacio h2 { margin-bottom: .2em; }
.vacio p { color: var(--tinta-2); font-size: var(--t4); margin: 0 0 1rem; }

/* ================================================================ resumen ==
 * El año en la casa. Pensado para enseñarlo en la comida de Navidad, así que
 * aquí sí se puede lucir: cifras enormes, una tarjeta por idea y nada más.
 */
.resumen-cifras { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.resumen-cifras .card { padding: 18px; }
.resumen-dato {
  font-family: var(--sans); font-size: var(--t-cifra); font-weight: 680;
  line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  display: block;
}
.resumen-dato small { font-size: .34em; font-weight: 600; color: var(--tinta-2); }
.resumen-etiqueta { display: block; font-size: var(--t5); color: var(--tinta-2); margin-top: .35rem; }

/* Podio: las tres primeras posiciones con altura distinta, el resto en lista.
 * Sin números encima del color, que la regla dura sigue en pie. */
.podio { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem;
  align-items: end; margin: 1rem 0 .4rem; }
.podio-col { text-align: center; }
.podio-barra {
  border-radius: 8px 8px 0 0; background: var(--color, var(--acento));
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.12);
}
.podio-nombre { display: block; font-size: var(--t5); margin-top: .35rem; }
.podio-cifra { display: block; font-family: var(--sans); font-weight: 700; font-size: var(--t3);
  font-variant-numeric: tabular-nums; }
.resumen-fotos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: .8rem; }
.resumen-fotos button { padding: 0; border: 0; background: var(--lienzo-2);
  border-radius: var(--radio-s); overflow: hidden; aspect-ratio: 1; cursor: zoom-in; }
.resumen-fotos img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* --- esperas y peticiones (fase E) --- */
.peticion {
  display: grid; grid-template-columns: auto 1fr; gap: .6rem;
  padding: .7rem 0; border-top: 1px solid var(--borde);
}
.peticion:first-child { border-top: 0; }
.peticion-cuerpo { min-width: 0; }
.peticion-cuerpo b { display: block; }
.peticion-cuerpo .sub { margin: 0 0 .1rem; font-size: var(--t5); }
.peticion-mensaje {
  margin: .3rem 0 .5rem; padding: .5rem .65rem; border-radius: var(--radio-s);
  background: var(--lienzo-2); font-size: var(--t4); color: var(--tinta);
  -webkit-user-select: text; user-select: text;
}
.peticion-acciones { display: flex; gap: .5rem; flex-wrap: wrap; }
.estado-pill {
  display: inline-block; font-size: var(--t5); font-weight: 600;
  padding: .1rem .5rem; border-radius: 999px;
}
.estado-pill.pendiente { background: var(--ojo-fondo); color: var(--ojo); }
.estado-pill.aceptada { background: var(--si-fondo); color: var(--si); }
.estado-pill.rechazada { background: var(--no-fondo); color: var(--no); }

/* ======================================================= escritorio ancho ==
 * Segundo bloque de escritorio, y va al FINAL del fichero a propósito: lo que
 * hay aquí pisa reglas que se declaran más abajo que el bloque de 780 px
 * (.parte, .podio, .fotos, .resumen-cifras...). Una media query no suma
 * especificidad, así que si esto viviera arriba no ganaría ninguna.
 */

/* --- retoques de componente en pantalla grande (siguen en una sola columna) --- */
@media (min-width: 780px) {
  .hueso-hero { min-height: 21rem; }   /* el esqueleto mide lo que va a medir el hero */

  /* El parte del tiempo: la columna del cielo es 1fr y se estiraba, dejando
   * 500 px de blanco entre "tormenta" y el "75%". Se acota la lista entera en
   * vez de reescribir sus cuatro columnas. El esqueleto lleva la misma rejilla,
   * así que se acota igual o el salto al llegar los datos vuelve. */
  .parte, .hueso-fila { max-width: 34rem; }

  /* Un podio con barras de 300 px de ancho no es un podio, es otra cosa. */
  .podio { max-width: 22rem; }

  /* Tres columnas fijas en 992 px daban miniaturas de 330 px. auto-fill parte
   * el ancho que haya en trozos de ~7rem y añade columnas según cabe. */
  .fotos, .resumen-fotos { grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr)); }
}

/* La quinta tarjeta de cifras del resumen se quedaba huérfana a media anchura:
 * la rejilla eran dos columnas clavadas y las tarjetas son cinco. Con auto-fit
 * se reparten las que haya. El suelo de 7,5rem está elegido a conciencia: en un
 * iPhone SE quedan 292 px útiles, dos columnas piden 252 y tres piden 384, así
 * que en el móvil se siguen viendo dos, exactamente como hasta ahora. */
.resumen-cifras { grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr)); }
/* No es .card ni .hero, así que se le escapaba la separación de abajo de
 * `.vista > *` y el podio quedaba pegado a las cifras. */
.vista > .resumen-cifras { margin-bottom: 12px; }

/* --- densidad con ratón ---
 * Los `min-height: 48px` de las filas de lista y los 44 de la fila del mapa de
 * calor son objetivo TÁCTIL: existen para el dedo de papá. Con un ratón sobran,
 * y de sobra: una checklist de seis líneas se comía media pantalla de portátil.
 * Va con `min-width` además de con el puntero porque un iPad con teclado dice
 * `pointer: fine` y sigue siendo una pantalla que se toca; en vertical mide 834
 * px y se queda fuera. En un portátil de verdad no hay caso. */
@media (hover: hover) and (pointer: fine) and (min-width: 1000px) {
  .fila-titular, .lista-elegir button, .marcas label, .lista-compra label { min-height: 38px; }
  .marcas label, .lista-compra label { padding-block: .45rem; }
  .lista-elegir button { padding-block: .55rem; }
  .heat-fila { min-height: 32px; }
  .leyenda-caja > summary { min-height: 34px; }
  .conmutador button { min-height: 36px; }
  .pastilla-agenda { min-height: 48px; padding-block: .55rem; }
}

/* --- el escritorio de verdad: navegación de pie y dos columnas ---
 * A partir de aquí deja de ser un móvil ancho. Una barra pegada abajo cruzando
 * 1280 px es lo que más delata que esto era una app de teléfono.
 */
@media (min-width: 1100px) {
  :root {
    --ancho-lectura: 62rem;   /* 992 px: el doble de una tarjeta cómoda más el hueco */
    --nav-lateral: 15rem;
  }

  /* OJO, ESTO NO ES COSMÉTICO. js/nucleo.js mide `.bottom-nav` con un
   * ResizeObserver y escribe --alto-nav como estilo EN LÍNEA sobre <html>, que
   * gana a cualquier regla de esta hoja. De pie, esa barra pasa a medir el alto
   * de la ventana, así que #app se llevaría 700 px de relleno abajo, la barra de
   * selección flotaría a media pantalla y los avisos saldrían por el techo.
   * Redefinirla en <body> no pelea con el estilo en línea: lo hereda todo lo que
   * cuelga de body, que es exactamente quien la usa. */
  body { --alto-nav: 0px; }

  #app { padding-left: var(--nav-lateral); }

  .bottom-nav {
    top: 0; bottom: 0; right: auto; width: var(--nav-lateral);
    /* Era una rejilla de cinco columnas: se pone de pie cambiando el eje, no
     * reescribiendo el componente. */
    grid-template-columns: 1fr; grid-auto-rows: max-content;
    align-content: start; justify-content: stretch; gap: 4px;
    /* Relleno propio, y NO `calc(var(--alto-cabecera) + algo)` para alinearla
     * con la primera tarjeta: la cabecera cambia de alto según la ruta (en el
     * calendario le crece la fila L M X J V S D), así que la navegación entera
     * daría un salto de 29 px cada vez que entras y sales del calendario. */
    padding: 16px 12px 14px;
    border-top: 0; border-right: 1px solid var(--borde);
  }
  .nav-item {
    flex-direction: row; justify-content: flex-start; gap: .7rem;
    padding: 9px 12px; min-height: 42px; border-radius: var(--radio-s);
    font-size: var(--t4);
  }
  .nav-item span { font-size: var(--t4); }
  .nav-item.activo { background: var(--acento-fondo); }
  /* La barrita de la pestaña activa gira con la barra: de tapa de arriba a canto
   * de la izquierda. Necesita `top` y `left` porque la versión de móvil se
   * apoyaba en la posición estática y aquí ya no vale. */
  .nav-item.activo::before {
    margin-top: 0; top: 50%; left: 0; transform: translateY(-50%);
    width: 3px; height: 62%; border-radius: 0 3px 3px 0;
  }

  /* Los elementos fijos no viven dentro de #app, así que el relleno de la
   * navegación no les llega: hay que apartarlos a mano. */
  .barra-seleccion { left: var(--nav-lateral); padding-inline: 24px; }
  .toast { left: calc(50% + var(--nav-lateral) / 2); }
  .hoja-panel { left: calc(50% + var(--nav-lateral) / 2); }

  /* --- DOS COLUMNAS ---
   * Ajustes son nueve tarjetas apiladas: tres pantallas de scroll para llegar a
   * "Salir". Libro, Montaña y la portada, lo mismo en menor grado. Las vistas
   * son una pila plana de .card, así que basta con volver rejilla el contenedor.
   * `align-items: start` para que una tarjeta corta no se estire hasta el alto
   * de la larga que tiene al lado: preferimos el borde de abajo irregular a
   * tarjetas medio vacías. */
  #vista-casa, #vista-cerler, #vista-libro, #vista-ajustes {
    display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start;
  }
  /* La separación la pone `gap`; el margen de abajo de `.vista > *` sumaría. */
  #vista-casa > *, #vista-cerler > *, #vista-libro > *, #vista-ajustes > * {
    margin-bottom: 0;
  }
  /* El hero es la escena del valle: partirlo por la mitad sería tirar lo único
   * que hace que esto no parezca un panel de control. */
  #vista-casa > .hero, #vista-cerler > .hero,
  #vista-casa > .hueso-hero, #vista-cerler > .hueso-hero { grid-column: 1 / -1; }
}

@media (min-width: 1500px) {
  :root { --ancho-lectura: 70rem; }
}
