/* ==========================================================================
   Froz3D — página principal de froz3d.com
   Marca Froz3D v4 (manual del 2026-09-28, kit en 03_MARCA_Y_MARKETING03_CODIGO_FUENTE/
   Froz3D_marca_y_logos/). Página clara: 60 % blanco hielo con texto azul profundo,
   30 % azul digital en acciones, 10 % cian / violeta / melocotón puntual.

   Tipografías: Manrope V5 by Mikhail Sharanda (licencia Manrope V5, uso web
   permitido sin modificar los archivos) · Inter de Rasmus Andersson (SIL OFL 1.1).
   ========================================================================== */

/* ---------- Tipografías (desde el kit, sin Google Fonts) ---------- */
@font-face {
  font-family: "Manrope V5";
  src: url("/assets/fonts/ManropeV5-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Manrope V5";
  src: url("/assets/fonts/ManropeV5-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Manrope V5";
  src: url("/assets/fonts/ManropeV5-ExtraBold.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
/* INTER:inicio — bloque escrito por tools/lab-froz3d-fuentes.py; no editarlo a mano.
   Inter va en dos archivos. El primero, recortado, trae lo que el sitio pinta. El segundo es el
   oficial completo, y el navegador lo descarga solo si aparece un carácter que el primero no
   tiene (por ejemplo, un nombre en checo escrito en el formulario). Los dos rangos no se
   solapan: si se solaparan, document.fonts.load cargaría los dos archivos.
   recortada: 288 caracteres, 70616 B, sha256 f3831b5848c7ae14a88e4352b32473fdd6cbd9d647251d1561c6ce0708f98fc8
   completa: 2564 caracteres
   funciones: calt ccmp cv11 kern locl mark mkmk ss01 tnum */
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/InterVariable-latin.woff2?v=2026-10-08-01") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000, U+0020-007E, U+00A0-00AC, U+00AE-00FF, U+0131, U+0152-0153, U+02BB-02BC,
    U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+2000-200B, U+2010-2027, U+202F-2055, U+2057, U+205F,
    U+20AC, U+2122, U+2191-2194, U+2197, U+2199, U+2212, U+FEFF;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/InterVariable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-0130, U+0132-0148, U+014A-0151, U+0154-01C3, U+01C5-0254, U+0256-027B,
    U+027E-0284, U+0286-0290, U+0292-02A4, U+02A6-02BA, U+02BD-02C5, U+02C7-02D9, U+02DB,
    U+02DD-0303, U+0306-0307, U+0309-030A, U+030C, U+030F, U+0313, U+0315, U+031B, U+0323,
    U+0326-0328, U+032C, U+0337-0338, U+0342-0343, U+0346-036F, U+0374-0376, U+037A-037F,
    U+0384-038A, U+038C, U+038E-03A1, U+03A3-03D7, U+03DC-03DD, U+03F0-03F6, U+03F9-03FA,
    U+03FC-0479, U+0480-049D, U+04A0-04FF, U+052F, U+0E3F, U+1D00, U+1D0D, U+1D1B, U+1D43,
    U+1D47-1D49, U+1D4D, U+1D4F-1D50, U+1D52, U+1D56-1D58, U+1D5B, U+1D62-1D65, U+1D9C, U+1DA0,
    U+1DBB, U+1DBF-1DF5, U+1DFC-1E9B, U+1E9D-1F15, U+1F18-1F1D, U+1F20-1F45, U+1F48-1F4D,
    U+1F50-1F57, U+1F59, U+1F5B, U+1F5D, U+1F5F-1F7D, U+1F80-1FB4, U+1FB6-1FC4, U+1FC6-1FD3,
    U+1FD6-1FDB, U+1FDD-1FEF, U+1FF2-1FF4, U+1FF6-1FFE, U+2070-2071, U+2074-208E, U+2090-209C,
    U+20A0-20AB, U+20AD-20AF, U+20B1-20B5, U+20B8-20BA, U+20BC-20C0, U+20DB-20DE, U+20E8, U+20F0,
    U+2100-2101, U+2103, U+2105-2106, U+2109, U+2113, U+2116-2117, U+211E-2121, U+2126, U+212A-212B,
    U+212E, U+2132, U+213B, U+214D, U+2150-217F, U+2183-2186, U+2189, U+2190, U+2195-2196, U+2198,
    U+21A9-21AA, U+21B0-21B1, U+21B3-21B5, U+21BA-21BB, U+21D0, U+21D2, U+21D4, U+21DE-21DF,
    U+21E4-21E5, U+21E7, U+21EA, U+2202, U+2205-2206, U+220F, U+2211, U+221A, U+221E, U+222B,
    U+2236, U+2248, U+2260, U+2264-2265, U+2295-2298, U+2303-2305, U+2318, U+2325-2327, U+232B,
    U+2380, U+2387, U+238B, U+23CE-23CF, U+2423, U+2460-2468, U+24B6-24CF, U+24EA, U+25A0-25A2,
    U+25AA, U+25B2-25B3, U+25B6-25B7, U+25BA-25BD, U+25C0-25C1, U+25C4-25C7, U+25CA-25CB, U+25CF,
    U+25E6, U+25EF, U+2600, U+2605-2606, U+263C, U+2661, U+2665, U+266A-266B, U+26A0, U+2713,
    U+2717, U+2756, U+2764, U+2780-2788, U+27EF, U+27F5-27FA, U+2913, U+2A38, U+2B06, U+2B12-2B13,
    U+2B1C, U+2B24, U+2C7C, U+2C7F, U+2DFF, U+2E18, U+A69F, U+A7FF, U+A92E, U+E000, U+E002-E05E,
    U+E06A-E0BD, U+E0C8-E0CC, U+E0DC-E0E6, U+E0F3-E0F5, U+E106, U+E109-E10A, U+E10C-E10F,
    U+E111-E113, U+E117-E118, U+E121-E122, U+E124, U+E12A-E15E, U+E163, U+E1C3, U+E1D2-E1DF,
    U+E1E1-E2DC, U+EE01-EE07, U+EE09-EE0A, U+EE0C-EE12, U+EE14, U+EE17, U+EE1D-EE45, U+EE47-EE84,
    U+EE87-EED6, U+EED8-EEE1, U+F6C3, U+1F12F-1F149, U+1F16A-1F16B, U+1F850, U+1F852;
}
/* INTER:fin */

/* ---------- Tokens ---------- */
:root {
  /* Marca v3 (guía p.7 y p.15). Los HEX son nominales; el logo manda. */
  --brand-primary: #102B46;      /* Azul profundo: identidad, texto principal */
  --text-primary: #102B46;
  --action-primary: #2457E6;     /* Azul digital: CTAs, activo, lecho */
  --accent-innovation: #705DC6;  /* Violeta: pieza, innovación */
  --brand-margin: #3DC8D9;       /* Cian hielo: margen, datos (nunca texto sobre claro) */
  --surface-page: #F7FAFC;       /* Blanco frío: fondo dominante */
  --accent-human: #E8BEA6;       /* Melocotón: solo comunicación con pacientes */
  --white: #FFFFFF;
  --dark-neutral: #161616;

  /* Derivados (documentados en LEEME.md, con su contraste) */
  --text-secondary: #3E546A;     /* 7,5:1 sobre blanco frío */
  --border: #D7DEE5;             /* decorativo */
  --border-control: #6B7C8F;     /* 4,3:1 sobre blanco: bordes de campos */
  --action-hover: #1D48C4;
  --action-active: #173B9F;
  --state-error: #B3261E;        /* siempre con la palabra «Error» */
  --on-dark-muted: #C9D3DD;      /* 9,5:1 sobre azul profundo */
  --navy-deep: #0C2339;          /* escenario del simulador */
  --human-tint: #F6E6DC;         /* melocotón aclarado: escenario del relato */
  --human-card: #FBF1EB;
  --action-tint: #EEF3FE;

  --font-display: "Manrope V5", "Manrope", "Segoe UI", system-ui, sans-serif;
  --font-text: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;

  --radius-control: 6px;
  --radius-card: 12px;
  --radius-panel: 20px;

  /* Contenedor: 1200 px hasta unos 1460 px de ventana; desde ahí, el 82 % del ancho, hasta 1560 px
     (a 1920 quedan 180 px a cada lado en vez de 360). Sobre 2000 px vuelve a crecer (0,75 px por
     px, hasta 1980 px): a 2560 quedan 290 px a cada lado (23 % del ancho entre los dos) en vez
     de 500 (39 %). Vale para toda la página: el encabezado fijo, el hero, la franja y las
     secciones comparten los mismos bordes. */
  --container: clamp(1200px, 82vw, clamp(1560px, 1560px + (100vw - 2000px) * 0.75, 1980px));
  --gutter: clamp(16px, 4vw, 40px);
  --section-pad: clamp(64px, 8vw, 120px);
  --header-h: 68px;

  --focus: var(--action-primary);
}

/* ---------- Base ---------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 16px);
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-primary);
  font-family: var(--font-text);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.55;
  font-feature-settings: "cv11", "ss01";
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; }
img { height: auto; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  margin: 0;
  text-wrap: balance;
}
p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; }
a { color: var(--action-primary); text-underline-offset: 0.18em; }
a:hover { color: var(--action-hover); }
sup { font-size: 0.62em; line-height: 0; vertical-align: 0.5em; }

[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.keep-case { text-transform: none !important; }

.salto {
  position: absolute;
  left: 16px; top: -60px;
  z-index: 100;
  padding: 10px 16px;
  background: var(--brand-primary);
  color: var(--white);
  font-family: var(--font-display);
  font-weight: 600;
  border-radius: var(--radius-control);
  text-decoration: none;
}
.salto:focus { top: 12px; color: var(--white); }

.contenedor {
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---------- Tipos de texto compartidos ---------- */
.eyebrow {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.8125rem;
  line-height: 1.3;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--action-primary);
  margin-bottom: 16px;
}
.eyebrow--oscuro { color: var(--brand-margin); }

.h-seccion {
  font-size: clamp(1.75rem, 1.25rem + 1.9vw, 2.625rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
  max-width: 24ch;
}
.entrada {
  margin-top: 20px;
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  line-height: 1.6;
  color: var(--text-secondary);
  max-width: 60ch;
}

/* ---------- Botones ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 12px 22px;
  border: 1.5px solid transparent;
  border-radius: var(--radius-control);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.btn--primario { background: var(--action-primary); color: var(--white); }
.btn--primario:hover { background: var(--action-hover); color: var(--white); }
.btn--primario:active { background: var(--action-active); }

.btn--secundario {
  background: transparent;
  color: var(--brand-primary);
  border-color: var(--brand-primary);
}
.btn--secundario:hover { background: rgba(16, 43, 70, 0.06); color: var(--brand-primary); }
.btn--secundario:active { background: rgba(16, 43, 70, 0.12); }

.btn--claro { background: var(--white); color: var(--brand-primary); }
.btn--claro:hover { background: var(--surface-page); color: var(--brand-primary); }

.btn--oscuro { background: var(--brand-primary); color: var(--white); }
.btn--oscuro:hover { background: #0A1D30; color: var(--white); }

.btn--sm { min-height: 40px; padding: 8px 16px; font-size: 0.9375rem; }
.btn--bloque { width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }

.btn-texto {
  background: none;
  border: 0;
  padding: 8px 4px;
  font: 600 0.9375rem/1.2 var(--font-display);
  color: var(--brand-primary);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}

/* ---------- Encabezado ---------- */
.cabecera {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--surface-page);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}
.cabecera.is-scrolled { border-bottom-color: var(--border); }
.cabecera__in {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: var(--header-h);
}
.marca { display: block; flex: none; }
.marca img { width: 160px; height: auto; }
.endoso {
  flex: none;
  padding-left: 16px;
  border-left: 1px solid var(--border);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  text-decoration: none;
}
.endoso:hover { color: var(--brand-primary); text-decoration: underline; }

.nav { margin-left: auto; }
.nav ul { display: flex; gap: 4px; list-style: none; }
.nav a {
  display: block;
  padding: 10px 12px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--brand-primary);
  text-decoration: none;
  border-radius: var(--radius-control);
}
.nav a:hover { background: rgba(16, 43, 70, 0.06); color: var(--brand-primary); }
@media (min-width: 1000px) { .nav__solo-movil { display: none; } }
.nav a[aria-current="true"] { color: var(--action-primary); box-shadow: inset 0 -2px 0 var(--action-primary); border-radius: 0; }

.nav-toggle {
  display: none;
  margin-left: auto;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 8px 12px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  font: 600 0.9375rem/1 var(--font-display);
  color: var(--brand-primary);
  cursor: pointer;
}
.nav-toggle__barras,
.nav-toggle__barras::before,
.nav-toggle__barras::after {
  display: block;
  width: 16px; height: 2px;
  background: currentColor;
  border-radius: 1px;
  content: "";
}
.nav-toggle__barras { position: relative; }
.nav-toggle__barras::before { position: absolute; top: -5px; }
.nav-toggle__barras::after { position: absolute; top: 5px; }

@media (max-width: 999px) {
  .nav-toggle { display: inline-flex; }
  .nav {
    position: absolute;
    left: 0; right: 0; top: 100%;
    margin: 0;
    background: var(--surface-page);
    border-bottom: 1px solid var(--border);
    padding: 8px var(--gutter) 16px;
  }
  .js .nav:not(.is-open) { display: none; }
  .nav ul { flex-direction: column; }
  .nav a { padding: 14px 8px; border-bottom: 1px solid var(--border); border-radius: 0; }
  .cabecera__cta { display: none; }
  .no-js .nav-toggle { display: none; }
  .no-js .cabecera { position: static; }
  .no-js .cabecera__in { flex-wrap: wrap; }
  .no-js .nav { position: static; flex-basis: 100%; padding: 0 0 8px; border-bottom: 0; }
  /* A11Y: la barra fija no debe tapar el elemento con foco. */
  html { scroll-padding-bottom: calc(84px + env(safe-area-inset-bottom)); }
  body { padding-bottom: 72px; }
}
@media (max-width: 480px) {
  .endoso { display: none; }
}

/* ---------- Hero ---------- */
/* Segunda iteración (pedido de Manuel, 2026-09-30): fondo claro continuo, la demostración 3D como
   protagonista de la columna visual y el texto más compacto (título en 4 líneas en escritorio).
   Desde el 2026-10-04, detrás de la escena va un fondo animado (ver más abajo); el texto sigue
   sobre el blanco frío. En escritorio el hero llena la primera pantalla y la sección de respaldos
   empieza justo debajo (ver «Escritorio: el hero llena la primera pantalla»).
   overflow-x: clip: el fondo llega al borde derecho de la ventana y nunca abre un desplazamiento
   horizontal (clip no crea contenedor de desplazamiento). */
.hero {
  position: relative;
  padding-block: clamp(32px, 3vw, 56px) clamp(24px, 2vw, 32px);
  isolation: isolate;
  overflow-x: clip;
}
/* Fondo animado (fondo-hero.js; pedido de Manuel, 2026-10-04). Reemplaza a la luz de ambiente
   azul: células en los violetas de la marca, como una lámina teñida vista al microscopio, que se
   mueven despacio detrás de la escena 3D, y solo ahí. Desde 1100 px ocupa la mitad derecha del
   hero (desde un poco antes del centro de la página hasta el borde de la ventana) y se desvanece
   hacia el texto, que sigue sobre el blanco frío salvo el final de las líneas del título, que el
   fondo alcanza a tocar; apilado (tableta y móvil, ver «Adaptación») va detrás del visor y se
   desvanece hacia arriba. Arriba y abajo se funde con la página: sin costura con el encabezado ni
   con la sección de respaldos, y casi sin tinte bajo los controles.
   Dos máscaras, cada una en su capa (sin mask-composite): la vertical en .hero__fondo, que sigue
   al lienzo del visor (--fondo-desde y --fondo-hasta, desde el tope del hero; las mide
   fondo-hero.js en px y aquí van valores de respaldo), y la horizontal en .hero__fondo-capa. Son
   solo de esta capa decorativa: la escena y sus contenedores siguen sin máscara, filtro ni
   opacidad. El degradado lila de la capa es el respaldo (sin JavaScript, sin WebGL 2, con ahorro
   de datos): el canvas lo cubre al dibujar su primer cuadro. */
/* --fondo-arranque: donde empieza a verse (apilado, 28 px antes del lienzo: bajo el texto, que
   queda a un hueco de columnas, 32 px o más). --fondo-fin: donde termina de apagarse, 150 px bajo
   el lienzo o en el borde del hero, lo que llegue primero (sin corte con la sección siguiente).
   Bajo el lienzo ya va al 30 %: los controles y la leyenda quedan casi sobre el blanco frío (su
   contraste lo mide tools/probar-hero.py sobre la captura del fondo). */
.hero__fondo {
  --fondo-desde: 38%;
  --fondo-hasta: 80%;
  --fondo-arranque: calc(var(--fondo-desde) - 28px);
  --fondo-fin: min(calc(var(--fondo-hasta) + 150px), 100%);
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent var(--fondo-arranque), #000 calc(var(--fondo-desde) + 64px),
    #000 calc(var(--fondo-hasta) - 72px), rgba(0, 0, 0, 0.3) calc(var(--fondo-hasta) + 10px), transparent var(--fondo-fin));
          mask-image: linear-gradient(to bottom, transparent var(--fondo-arranque), #000 calc(var(--fondo-desde) + 64px),
    #000 calc(var(--fondo-hasta) - 72px), rgba(0, 0, 0, 0.3) calc(var(--fondo-hasta) + 10px), transparent var(--fondo-fin));
}
/* La caja de la capa no depende de las medidas (si se moviera al llegar el JavaScript contaría como
   desplazamiento de diseño): solo las máscaras siguen al lienzo. */
.hero__fondo-capa {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, rgba(112, 93, 198, 0.12) 0%, rgba(112, 93, 198, 0.2) 58%, rgba(36, 87, 230, 0.13) 100%);
}
/* El canvas del fondo solo cubre la franja que la máscara deja ver (fondo-hero.js lo crea con las
   medidas ya puestas) y aparece con un fundido sobre el degradado de respaldo. */
.hero__fondo-lienzo {
  position: absolute;
  top: max(0px, var(--fondo-arranque));
  left: 0;
  width: 100%;
  height: calc(var(--fondo-fin) - max(0px, var(--fondo-arranque)));
  opacity: 0;
  transition: opacity 0.6s ease;
}
.hero__fondo--listo .hero__fondo-lienzo { opacity: 1; }
/* Escritorio: la mitad del visor y un poco más. Manuel pidió (2026-10-04, al ver la primera versión,
   que partía en el centro de la página) que el fondo alcance a tocar las letras, «apenas un poco»:
   la capa parte antes del centro, casi transparente, pasa bajo el final de las líneas del título a
   menos de un cuarto de su tinte y llega a pleno a 4/10 de la capa, ya sobre el visor. Cuánto
   antes: 10vw en pantallas de 1440 px o más; en las más angostas, menos (40 px a 1100), porque
   ahí la bajada llena casi toda su columna y quedaría sobre el fondo. Así la bajada, el botón y el
   enlace para pacientes siguen sobre el blanco frío. Arriba se funde desde el borde del hero. */
@media (min-width: 1100px) {
  .hero__fondo {
    --fondo-desde: 8%;
    --fondo-hasta: 76%;
    --fondo-arranque: 0px;
  }
  .hero__fondo-capa {
    left: calc(50% - min(10vw, 40px + (100vw - 1100px) * 0.3));
    -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 0.06) 5%, rgba(0, 0, 0, 0.15) 10%,
      rgba(0, 0, 0, 0.3) 17%, rgba(0, 0, 0, 0.55) 25%, rgba(0, 0, 0, 0.82) 33%, #000 40%);
            mask-image: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 0.06) 5%, rgba(0, 0, 0, 0.15) 10%,
      rgba(0, 0, 0, 0.3) 17%, rgba(0, 0, 0, 0.55) 25%, rgba(0, 0, 0, 0.82) 33%, #000 40%);
  }
}
/* «Pausar fondo» (WCAG 2.2.2): un botón redondo y chico en la esquina del visor, a la altura del
   pie, fuera del flujo (nada se mueve cuando fondo-hero.js lo muestra; solo aparece si hay
   animación que detener). Dos barras para pausar, un triángulo para reanudar; el nombre lo lleva
   el texto oculto. Relleno blanco: el borde contrasta con el botón, no con el fondo que se mueve. */
.hero__fondo-pausa {
  position: absolute;
  right: var(--gutter);   /* el borde del contenido: .contenedor lleva el margen como relleno */
  bottom: -3px;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 0;
  background: var(--white);
  border: 1px solid var(--border-control);
  border-radius: 50%;
  color: var(--brand-primary);
  cursor: pointer;
  transition: border-color 0.18s ease;
}
.hero__fondo-pausa:hover { border-color: var(--brand-primary); }
.hero__fondo-pausa:focus-visible { border-radius: 50%; }
.hero__fondo-pausa::before {
  content: "";
  width: 8px;
  height: 8px;
  background: linear-gradient(to right, currentColor 0 3px, transparent 3px 5px, currentColor 5px 8px);
}
.hero__fondo-pausa[data-modo="reanudar"]::before {
  width: 7px;
  margin-left: 2px;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
/* El pie del visor le guarda su lugar (siempre, con JavaScript: nada se mueve cuando aparece). */
.js .visor__pie { padding-right: 32px; }
/* Escritorio de hasta 1079 px de alto (1536×864, 1440×900, 1366×768…; a 1920×1080 ya cabe con
   los márgenes de arriba): los márgenes del hero crecen con el alto de la ventana en vez de
   saltar: 20/12 px hasta 780 px de alto y, desde unos 925 px, los de .hero (56/32 px a 1920;
   menos en ventanas angostas: el tope es el mismo clamp, así que no hay salto al pasar de 1079 a
   1080 px). vh antes de svh. */
@media (min-width: 1100px) and (max-height: 1079px) {
  .hero {
    padding-block:
      clamp(20px, 20px + (100vh - 780px) * 0.25, clamp(32px, 3vw, 56px))
      clamp(12px, 12px + (100vh - 780px) * 0.15, clamp(24px, 2vw, 32px));
    padding-block:
      clamp(20px, 20px + (100svh - 780px) * 0.25, clamp(32px, 3vw, 56px))
      clamp(12px, 12px + (100svh - 780px) * 0.15, clamp(24px, 2vw, 32px));
  }
}
/* Escritorio: el hero llena la primera pantalla (bajo el encabezado y su filete de 1 px), con el
   texto y el visor centrados en vertical, y la sección de respaldos empieza justo debajo, en el
   pliegue: nada asoma cortado en el borde. El tope (900 px, o el 62 % del ancho en pantallas
   anchas) evita un hero desmedido en monitores verticales. vh antes de svh. */
@media (min-width: 1100px) {
  .hero {
    display: grid;
    align-content: center;
    min-height: min(calc(100vh - var(--header-h) - 1px), max(900px, 62vw));
    min-height: min(calc(100svh - var(--header-h) - 1px), max(900px, 62vw));
  }
}
/* --hueco-columnas: espacio entre el texto y el visor (72 px desde 1600). position: relative para
   «Pausar fondo», que va en su esquina. */
.hero__rejilla {
  --hueco-columnas: clamp(32px, 4vw, 56px);
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--hueco-columnas);
  align-items: start;
}
.hero__texto { grid-column: 1 / span 6; }
.visor { grid-column: 7 / span 6; }

/* Título: cada frase va entera (white-space: nowrap en .hero__frase) y el ancho decide cuántas
   entran por línea: en móvil «Cirugía oncológica / de precisión: / trazabilidad 3D / de
   márgenes / en tiempo real.»; desde tableta el tramo en azul empieza línea (ver «Adaptación» y
   «Escritorio: la demostración manda»). text-wrap: wrap y no balance: el reparto por frases ya
   da líneas parejas y balance podía bajar «de márgenes» a la última línea. */
.hero__titulo {
  font-size: clamp(1.875rem, 1.2rem + 3.4vw, 3.5rem);
  line-height: 1.06;
  letter-spacing: -0.022em;
  max-width: 18ch;
  text-wrap: wrap;
}
.hero__frase { white-space: nowrap; }
.hero__titulo .acento { color: var(--action-primary); }
/* Al terminar la intro, intro-marca.js le da el foco al título (con tabindex="-1") para que el
   lector de pantalla siga desde ahí. No es un control ni entra en el orden del tabulador, así que
   ese foco programático no dibuja anillo; los controles conservan el suyo (:focus-visible). Si el
   título llegara a ser una parada del tabulador, esta regla se quita. */
.hero__titulo[tabindex="-1"]:focus { outline: none; }
.hero__sub {
  margin-top: 20px;
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  line-height: 1.55;
  color: var(--text-secondary);
  max-width: 44ch;
}
.hero__acciones {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 28px;
}
/* Acceso para pacientes y familiares: un enlace de texto secundario, sin fondo (la píldora
   melocotón competía con «Agendar demo clínica 1 a 1», la acción principal). Gris secundario
   subrayado (7,5:1 sobre el blanco frío) y azul digital con el mouse. Blanco táctil de 24 px de
   alto (44 en móvil). */
.hero__paciente {
  display: table;
  margin-top: 14px;
  padding-block: 2px;
  color: var(--text-secondary);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 20px;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
}
.hero__paciente:hover { color: var(--action-primary); }
/* Escritorio bajo 820 px de alto: la bajada y el CTA se acercan un poco (el visor ya manda el alto
   del hero, pero así el texto no queda más alto que él en ventanas bajas). */
@media (min-width: 1100px) and (max-height: 819px) {
  .hero__sub { margin-top: 16px; }
  .hero__acciones { margin-top: 22px; }
  .hero__paciente { margin-top: 10px; }
}

/* ---------- Respaldos: sección justo bajo el hero ----------
   Tercera ronda de Manuel (2026-09-29): la sección que sigue al hero, más grande, sin título propio
   y sin líneas (ni panel, ni bordes, ni divisiones). Dos mitades con su rótulo (h2), de 3 celdas
   cada una: a la izquierda «Validación clínica y científica» y a la derecha «Respaldo
   institucional y aceleración». Desde 1100 px, lado a lado; de 700 a 1099, una sobre otra (las
   columnas calzan: las dos son de 3); bajo 700, una fila (ver «Módulo: franja de respaldos», al
   final). Cada celda lleva sus logos en una banda de alto fijo (así los textos quedan alineados) y
   el texto debajo. Alturas equilibradas a ojo por proporción y peso: los anchos o macizos
   (Start-Up Chile, el título de AHNS, el texto de Babson) van más bajos que los compactos (FALP,
   SLAP, 3IE); en celdas angostas, los logos de una celda se achican juntos (object-fit) antes que
   desbordar. Logos en gris suave, con su color al pasar el mouse o con el foco del teclado. El
   gris es solo de esta sección: la intro y Evidencia muestran los mismos archivos a color. */
.respaldos.seccion { padding-block: clamp(40px, 4.5vw, 72px) 0; }   /* abajo, el aire es el de la sección 01 */
.respaldos__cabeza { display: flex; justify-content: flex-end; }
.respaldos__juego { display: grid; row-gap: clamp(36px, 4vw, 56px); }
.respaldos__rotulo {
  margin: 0 0 18px;
  font: 700 0.875rem/1.3 var(--font-display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--action-primary);   /* como .eyebrow: 5,6:1 sobre el blanco frío */
}
.confianza {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px 24px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.confianza__item {
  position: relative;       /* ancla del globo */
  display: flex;            /* el enlace ocupa la celda entera */
  min-width: 0;
}
/* Cada celda entera enlaza a la página de su institución, en una pestaña nueva (pedido de Manuel,
   2026-09-29). Al pasar el mouse, el logo toma su color y el texto se subraya en azul acción; con
   teclado, el foco rodea la celda. */
.confianza__enlace {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  min-width: 0;
  padding: 12px 4px;
  color: inherit;
  text-align: center;
  text-decoration: none;
}
.confianza__enlace:focus-visible { border-radius: 8px; }
.confianza__marca {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;                 /* el PNG de la USM ya trae aire a la izquierda */
  max-width: 100%;
  height: 64px;
}
.confianza__logo {
  flex: 0 1 auto;
  min-width: 0;
  width: auto;
  max-width: 100%;
  height: var(--alto-logo);
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.65;
  transition: filter 0.2s ease, opacity 0.2s ease;
}
.confianza__logo--falp { --alto-logo: 62px; }    /* con su lema: el isotipo pide alto */
.confianza__logo--slap { --alto-logo: 56px; }
.confianza__logo--3ie { --alto-logo: 44px; }     /* disco lleno: pesa más que su alto */
.confianza__logo--usm { --alto-logo: 52px; }     /* el PNG trae aire: el escudo mide ~40 px */
.confianza__logo--suc { --alto-logo: 40px; }
.confianza__logo--ahns { --alto-logo: 28px; }    /* título en dos líneas, 10 veces más ancho que alto */
.confianza__logo--babson { --alto-logo: 22px; }  /* solo el texto (8,3 veces más ancho que alto) */
.confianza__enlace:focus-visible .confianza__logo { filter: none; opacity: 1; }
.confianza__txt {
  font: 600 1rem/1.35 var(--font-display);
  color: var(--brand-primary);
  text-wrap: balance;
}
/* «Start-Up» no se corta en el guion (el texto no cambia: solo se envuelve). */
.confianza__txt .sin-corte { white-space: nowrap; }
.respaldos .respaldos__nota { margin-top: clamp(24px, 3vw, 40px); line-height: 1.4; }
/* Con mouse, la celda entera (también su globo) devuelve el color al logo. */
@media (hover: hover) and (pointer: fine) {
  .confianza__item:hover .confianza__logo { filter: none; opacity: 1; }
  .confianza__enlace:hover .confianza__txt {
    color: var(--action-primary);
    text-decoration: underline;
    text-underline-offset: 3px;
  }
}
@media (min-width: 1100px) {
  .respaldos__juego { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(48px, 6vw, 112px); }
}

/* ---------- Visor 3D: la demostración integrada al hero (2026-09-30, segunda iteración) ----------
   Pedido de Manuel: sin tarjeta, sin la lente oscura y sin efectos; la animación interactiva como
   protagonista, integrada al fondo claro, con sus controles agrupados bajo la escena. .visor es
   solo el contenedor (sin fondo, borde ni relleno; las pruebas miden su rectángulo). La escena usa
   el tema «heroe» de pasos3d.js (trazos, guías y rótulos en azul profundo, pensados para el blanco
   frío) y un encuadre que nunca corta la cabeza. Nada de desenfoque, máscara ni opacidad global
   sobre el lienzo ni sobre sus contenedores: la escena queda nítida. Bajo la escena, en este orden
   (el del HTML y el del tabulador): la barra de controles («Ver los 4 pasos», los números 1 a 4 y,
   al final, «Ver presentación»), la frase del paso, pegada a sus controles, y el pie, secundario:
   «Vista esquemática» y la leyenda. */
.visor {
  --visor-hueco: 16px;
  margin: 0;
}

/* El lienzo: una caja sin relleno, borde, radio ni transformación (la intro lee su rectángulo
   para aterrizar y pasos3d.js su caja de contenido: tienen que coincidir). Su alto nunca depende de
   lo que tiene adentro: proporción en móvil y tableta, alto fijo en escritorio. */
.visor__lienzo {
  position: relative;
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  touch-action: pan-y;
}
/* Póster (sin 3D, o mientras carga): el icono cerrado de la marca en su variante clara. Chico a
   propósito: el candidato a LCP debe seguir siendo el título del hero. */
.visor__poster {
  width: min(46%, 260px);
  height: auto;
}
.visor__lienzo canvas {
  position: absolute;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
}

/* Barra de controles bajo la escena: «Ver los 4 pasos», los números y, al final (a la derecha),
   «Ver presentación». Sin caja: un grupo alineado con el borde de la columna, como el texto. Si
   no caben (móvil), los números y «Ver presentación» bajan a otra fila. */
.visor__barra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-top: var(--visor-hueco);
}

/* Botón «Ver los 4 pasos» / «Pausar» (WCAG 2.2.2): va antes de los pasos, bajo el lienzo. El
   icono cambia con el modo (triángulo o dos barras) y el texto dice lo que hará. Sobre la página
   clara: texto azul profundo y borde de control (#6B7C8F, 4,1:1 sobre el blanco frío). */
.visor__controles {
  display: flex;
  flex-wrap: wrap;
  max-width: 100%;
  align-items: center;
  gap: 12px;
  transition: opacity 0.3s ease-out 0.05s;
}
/* Ancho mínimo de «Ver los 4 pasos» (11em = 143 px: 137 con Manrope, hasta 143 con la letra de
   respaldo): con «Pausar», más corto, o al cargar la letra, los números de al lado no se corren. */
.visor__reproducir {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 11em;
  gap: 9px;
  min-height: 36px;
  padding: 6px 14px 6px 12px;
  background: transparent;
  border: 1px solid var(--border-control);
  border-radius: 999px;
  color: var(--brand-primary);
  font: 600 0.8125rem/1 var(--font-display);
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease;
}
.visor__reproducir:hover { border-color: var(--brand-primary); background: rgba(16, 43, 70, 0.06); }
.visor__reproducir::before {
  content: "";
  flex: none;
  width: 9px;
  height: 10px;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.visor__reproducir[data-modo="pausar"]::before {
  width: 9px;
  background: linear-gradient(to right, currentColor 0 3px, transparent 3px 6px, currentColor 6px 9px);
  clip-path: none;
}

/* Los 4 pasos: solo los números, en círculos. El del paso marcado (aria-current) va relleno en
   azul profundo, con el número en blanco (14,4:1). Cada botón se llama «Paso N» y lleva su frase
   como descripción. Sin JavaScript no se muestran (no harían nada): el recuadro de abajo lista
   las 4 frases. */
.visor__pasos {
  display: flex;
  gap: 8px;
  list-style: none;
}
.no-js .visor__pasos { display: none; }
.visor__paso {
  display: grid;
  place-items: center;
  width: var(--paso-tam, 36px);
  height: var(--paso-tam, 36px);
  padding: 0;
  background: transparent;
  border: 1.5px solid var(--border-control);
  border-radius: 50%;
  color: var(--brand-primary);
  font: 800 0.875rem/1 var(--font-display);
  cursor: pointer;
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}
.visor__paso:hover { background: rgba(16, 43, 70, 0.06); border-color: var(--brand-primary); }
.visor__paso:focus-visible { border-radius: 50%; }
.visor__paso[aria-current="step"] { background: var(--brand-primary); border-color: var(--brand-primary); color: var(--white); }

/* «Ver presentación» (repite la intro de marca a pantalla completa): acción secundaria, como
   enlace de texto, al final de la barra. Nace oculto y lo muestra intro-marca.js al cargar: con
   JavaScript su lugar queda guardado (invisible e inerte), así la barra no se mueve cuando
   aparece. */
.visor__presentacion {
  margin-left: auto;
  min-height: var(--presentacion-alto, 36px);
  padding: 6px 2px;
  background: none;
  border: 0;
  color: var(--text-secondary);
  font: 600 0.8125rem/1 var(--font-display);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  cursor: pointer;
}
.visor__presentacion:hover { color: var(--action-primary); }
.js .visor__presentacion[hidden] {
  display: inline-block !important;
  visibility: hidden;
}

/* Recuadro de la frase, pegado a los controles. Con JavaScript, las 4 frases van apiladas en la
   misma celda: el recuadro mide lo que la más larga y no cambia de alto al pasar de un paso a
   otro. Solo se ve la del paso marcado, y solo con el texto abierto (data-texto en la figura, lo
   pone visor3d.js al pinchar un número o «Ver los 4 pasos»). Sin JavaScript, las 4 frases en
   lista. */
.visor__texto {
  display: grid;
  gap: 8px;
  margin-top: 10px;
}
.visor__frase {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: 10px;
  align-items: start;
  margin: 0;
  color: var(--text-primary);
  font: 400 0.875rem/1.45 var(--font-text);
}
.visor__frase-num {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  margin-top: -1px;
  border-radius: 50%;
  background: var(--brand-primary);
  color: var(--white);
  font: 800 0.75rem/1 var(--font-display);
}
/* Líneas parejas: el paso 4 no deja «y tragar.» solo en su segunda línea. */
.visor__txt { text-wrap: balance; }
.visor__txt strong { font-weight: 700; }
.js .visor__texto {
  gap: 0;
  padding: 10px 14px;
  border: 1px solid transparent;
  border-radius: 10px;
}
/* Las frases más cortas van centradas en el alto que da la más larga. */
.js .visor__frase { grid-area: 1 / 1; align-self: center; visibility: hidden; }
/* Abierto: fondo celeste suave con filete azul digital a la izquierda, como el recuadro de la
   conclusión de la sección 01 (.argumento). */
.js .visor[data-texto] .visor__texto {
  background: var(--action-tint);
  box-shadow: inset 3px 0 0 var(--action-primary);
}
.js .visor[data-texto="1"] [data-visor-frase="1"],
.js .visor[data-texto="2"] [data-visor-frase="2"],
.js .visor[data-texto="3"] [data-visor-frase="3"],
.js .visor[data-texto="4"] [data-visor-frase="4"] { visibility: visible; }
/* Ayuda (pedido de Manuel, 2026-09-29): con la frase cerrada, el lugar guardado del recuadro dice
   cómo abrirla. Solo con JavaScript y desde 1100 px (bajo eso, el recuadro cerrado no ocupa
   lugar); al abrir una frase se esconde. */
.visor__ayuda {
  display: none;
  margin: 0;
  color: var(--text-secondary);
  font: 500 0.8125rem/1.45 var(--font-text);
}
.js .visor__ayuda { display: block; grid-area: 1 / 1; align-self: center; }
.js .visor[data-texto] .visor__ayuda { visibility: hidden; }
/* Bajo 1100 px, cerrado, el recuadro no ocupa lugar (abrirlo corre lo de abajo, siempre por un
   clic). Desde 1100 px guarda su alto: nada se mueve al abrirlo o cerrarlo. */
@media (max-width: 1099px) {
  .js .visor:not([data-texto]) .visor__texto { display: none; }
}

/* Pie, en un nivel secundario: «Vista esquemática» (el nombre de la figura) y la leyenda, en letra
   chica y gris secundario (7,5:1). */
.visor__pie {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 18px;
  margin-top: 12px;
}
.visor__rotulo {
  margin: 0;
  font: 700 0.6875rem/1.3 var(--font-display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.leyenda {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  list-style: none;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-secondary);
}
/* Como la leyenda de Pacientes (.rl-leyenda): cada muestra con un contorno azul profundo de 1,5 px
   (el cian del borde no se distingue solo sobre claro). */
.leyenda li { display: inline-flex; align-items: center; gap: 7px; }
.leyenda__muestra { width: 12px; height: 12px; border-radius: 3px; flex: none; box-shadow: 0 0 0 1.5px var(--brand-primary); }
.leyenda__muestra--lecho { background: var(--action-primary); }
.leyenda__muestra--pieza { background: var(--accent-innovation); }
.leyenda__muestra--margen { height: 4px; border-radius: 2px; background: var(--brand-margin); }
/* Leyenda por paso (data-paso lo pone visor3d.js): lo que todavía no aparece en la escena va
   atenuado, sin cambiar el texto. En los pasos 1 y 2 el tejido es melocotón y la pieza lila:
   «Pieza retirada» y «Zona operada» se atenúan hasta el paso 3, y «Borde a revisar» hasta el 2.
   La muestra baja al 45 %; el texto, al gris de la leyenda de Pacientes (#5B6B7C, 5,2:1 sobre el
   blanco frío). Solo con el 3D a la vista (.visor3d--listo): el póster muestra el logo con los
   tres colores. */
.visor .leyenda li { transition: color 0.3s ease; }
.visor .leyenda__muestra { transition: opacity 0.3s ease; }
.visor3d--listo[data-paso="1"] .leyenda li,
.visor3d--listo[data-paso="2"] .leyenda li:not(:last-child) { color: #5B6B7C; }
.visor3d--listo[data-paso="1"] .leyenda__muestra,
.visor3d--listo[data-paso="2"] .leyenda li:not(:last-child) .leyenda__muestra { opacity: 0.45; }

/* ---------- Secciones ---------- */
.seccion { padding-block: var(--section-pad); }
.seccion--blanca { background: var(--white); }
.seccion--oscura {
  --focus: var(--brand-margin);
  background: var(--brand-primary);
  color: var(--white);
}
.seccion--oscura .entrada { color: var(--on-dark-muted); }
.seccion__cabeza--ancha { margin-bottom: clamp(32px, 4vw, 56px); }

.rejilla-2 {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(32px, 5vw, 72px);
}
.rejilla-2 > .seccion__cabeza { grid-column: 1 / span 5; }
.rejilla-2 > :last-child { grid-column: 6 / span 7; }

/* ---------- 2. Problema ---------- */
/* Dos columnas (2026-09-30): a la izquierda el problema (fila 1) y la conclusión al pie (fila 2,
   pegada abajo: termina con la fuente de las cifras); a la derecha las cifras, en las dos filas.
   En tableta y celular, una columna en el orden del HTML: problema → cifras → conclusión.
   Tamaños de texto: título, entrada y texto normal; la fuente y las escalas, en letra chica. */
.problema > .seccion__cabeza { grid-row: 1; }
.problema > .problema__datos { grid-column: 6 / span 7; grid-row: 1 / span 2; }
.problema > .argumento { grid-column: 1 / span 5; grid-row: 2; align-self: end; }

.problema__rotulo {
  margin-bottom: 20px;
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-secondary);
  max-width: 48ch;
}

.argumento {
  padding: 20px 24px;
  border-left: 3px solid var(--action-primary);
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
  background: var(--action-tint);
  line-height: 1.55;
  max-width: 52ch;
}
.argumento strong {
  display: block;
  margin-top: 8px;
  font-family: var(--font-display);
  font-weight: 700;
}

/* Cifras de Miller et al. (2024). problema.js las anima una vez por fila, solo con transform y
   opacity (más --cifra-linea para el filete); sin JS, con movimiento reducido y al imprimir
   rige este estado final tal cual. */
.cifras { display: grid; gap: 0; }
/* Las tres filas con la misma forma: la cifra en una columna de ancho fijo, centrada en alto, y a
   su derecha la frase (arriba) y el gráfico (abajo). Así cifras, frases y gráficos empiezan en la
   misma vertical en las tres. */
.cifra {
  position: relative;
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  column-gap: 28px;
  row-gap: 12px;
  align-items: center;
  padding-block: 25px 24px; /* 1 px arriba para el filete, que no ocupa lugar */
}
/* Filete superior como capa propia, para dibujarlo de izquierda a derecha (--cifra-linea, de 0
   a 1). Es un borde y no un fondo: así sigue visible con colores forzados. Va en las tres filas:
   la primera lo separa del rótulo. */
.cifra::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  border-top: 1px solid var(--border);
  transform: scaleX(var(--cifra-linea, 1));
  transform-origin: 0 50%;
}
/* Antes de que llegue problema.js: si las cifras van a animarse, el script del <head> marca
   html.cifras-pendientes y las filas se ocultan (como su cuadro 0, que también es invisible), así
   su estado final no asoma para luego volver a 0. El módulo quita la clase al prepararlas. Si no
   llega, se muestran solas a los 3 s. Al imprimir, siempre a la vista. */
.cifras-pendientes [data-cifra] > *,
.cifras-pendientes [data-cifra]::before {
  opacity: 0;
  animation: cifras-respaldo 0s 3s forwards;
}
@keyframes cifras-respaldo { to { opacity: 1; } }
@media print {
  .cifras-pendientes [data-cifra] > *,
  .cifras-pendientes [data-cifra]::before { opacity: 1; animation: none; }
}
.cifra__valor {
  grid-row: span 2;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.5rem, 1.75rem + 2vw, 3.5rem);
  line-height: 1;
  white-space: nowrap;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--brand-primary);
}
/* Número de ancho fijo. Mientras cuenta, el original queda en su sitio, transparente: solo él
   fija el ancho y es lo único que leen, seleccionan y copian. Encima va la copia que cuenta
   (aria-hidden), fuera del flujo, con la misma caja que el original y alineada a la derecha: la
   caja no cambia de un valor a otro (sin desplazamientos de diseño) y la coma y la unidad no se
   mueven. Su número es contenido generado (data-n, problema.js), no texto del DOM. */
.cifra__num { display: inline-block; position: relative; }
.cifra__num-original { color: transparent; }
.cifra__num-vivo { position: absolute; inset: 0; text-align: right; white-space: nowrap; }
.cifra__num-vivo::after { content: attr(data-n); }
.cifra__unidad {
  font-size: 0.45em;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--text-secondary);
}
.cifra__texto { color: var(--text-secondary); max-width: 44ch; align-self: end; }
/* Los dos tipos de gráfico miden lo mismo y cuelgan bajo la frase. */
.cifra > .regla,
.cifra > .proporcion { align-self: start; max-width: 360px; }

/* Regla: las marcas crecen desde la base y la base se traza desde el 0 (fill-box: el origen es
   el de cada trazo). La marca se alarga desde el eje del tramo al asentarse. */
.regla { width: 100%; height: auto; overflow: visible; }
.regla__ticks line {
  stroke: var(--brand-primary);
  stroke-width: 1;
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
.regla__base {
  stroke: var(--brand-primary);
  stroke-width: 1;
  transform-box: fill-box;
  transform-origin: 0 50%;
}
.regla__tramo { fill: var(--action-primary); }
.regla__brillo { opacity: 0; }
.regla__marca {
  stroke: var(--brand-primary);
  stroke-width: 2;
  transform-box: fill-box;
  transform-origin: 50% 83%;
}
/* 13 unidades del SVG: con la regla a 360 px se leen a unos 11,7 px, como la escala de las barras.
   En pantallas muy angostas la regla se achica; ahí 15 unidades (unos 10,8 px a 320). */
.regla__txt { font: 500 13px var(--font-text); fill: var(--text-secondary); }
@media (max-width: 379px) {
  .regla__txt { font-size: 15px; }
}

/* Barras de proporción (0 a 100 %). La pista redondeada recorta el fondo y el relleno: el
   extremo izquierdo siempre es redondo y el derecho queda recto contra el borde azul profundo,
   que marca el valor exacto como la marca de la regla. Al animar, el fondo, el relleno y el
   carro del borde se deslizan (transform) y el brillo, un reflejo justo detrás del frente de
   avance, se enciende y se apaga (opacity). La pista mide 8 px, como el tramo de la regla, y
   debajo va su escala 0 · 50 · 100 % (el margen inferior le guarda el lugar). */
.proporcion {
  position: relative;
  height: 8px;
  width: 100%;
  margin-block: 10px 22px;
}
.proporcion__pista {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  overflow: hidden;
}
.proporcion__fondo,
.proporcion__relleno {
  position: absolute;
  inset: 0 auto 0 0;
}
.proporcion__fondo { width: 100%; background: var(--border); }
.proporcion__relleno { width: var(--p); background: var(--action-primary); }
.proporcion__brillo {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(64px, 100%);
  background: linear-gradient(90deg, rgb(255 255 255 / 0), rgb(255 255 255 / 0.42) 72%, rgb(255 255 255 / 0));
  opacity: 0;
}
.proporcion__carro {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.proporcion__borde {
  position: absolute;
  top: -5px;
  bottom: -5px;
  left: var(--p);
  width: 2px;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--brand-primary);
}
/* Cada rótulo en su posición exacta (0, mitad y final), como los de la regla. Sin transform:
   problema.js lo usa para que suban al aparecer. */
.proporcion__escala {
  position: absolute;
  inset: calc(100% + 5px) 0 auto;
  font: 500 0.75rem/1 var(--font-text);
  color: var(--text-secondary);
  pointer-events: none;
}
.proporcion__escala > span { position: absolute; top: 0; white-space: nowrap; }
.proporcion__escala > :first-child { left: 0; }
.proporcion__escala > :nth-child(2) { left: 50%; width: 4ch; margin-left: -2ch; text-align: center; }
.proporcion__escala > :last-child { right: 0; }
/* Colores forzados: el número original sigue transparente mientras cuenta y las barras
   conservan sus colores (si no, el fondo forzado las borra). */
@media (forced-colors: active) {
  .cifra__num-original,
  .proporcion { forced-color-adjust: none; }
}
.fuente {
  margin-top: 8px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--text-secondary);
}

/* ---------- 3. Solución ---------- */
/* Tarjetas de la solución: esta es la grilla con todo a la vista, el estado final sin JavaScript,
   si solucion.js no llega y al imprimir. La ilustración va arriba (el cuerpo y su interior se funden
   con display: contents para ordenarla), entera y sin recorte (kit Froz3D_tarjetas_solucion_v2);
   luego número, título y texto. Con el módulo, el acordeón está en «Módulo: Tarjetas de la
   solución». */
.tarjetas {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  list-style: none;
}
.tarjeta {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 22px 22px 26px;
  background: var(--surface-page);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}
.tarjeta__cuerpo,
.tarjeta__cuerpo-in { display: contents; }
.tarjeta__portada { display: none; }
.tarjeta__marco { order: 1; display: block; aspect-ratio: 1; margin-bottom: 18px; }
.tarjeta__img,
.tarjeta__mini {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  border-radius: var(--radius-card);
}
.tarjeta__titulo { order: 2; font-size: 1.1875rem; line-height: 1.25; }
.tarjeta__num {
  display: block;
  margin-bottom: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  color: var(--action-primary);
  font-variant-numeric: tabular-nums;
}
.tarjeta__cuerpo-in > p { order: 3; margin-top: 10px; color: var(--text-secondary); font-size: 0.975rem; }
/* El botón que solucion.js pone en cada título no se nota: toma la letra y el color del título. */
.tarjeta__boton {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: inherit;
  text-transform: none;
  -webkit-appearance: none;
  appearance: none;
}
.solucion__nota {
  margin-top: 14px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--text-secondary);
}

.caps { grid-column: 1 / span 7; }
.caps__titulo { font-size: 1.375rem; line-height: 1.2; margin-bottom: 20px; }
.caps__lista { list-style: none; }
.cap {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr);
  gap: 8px;
  padding: 18px 12px 18px 8px;
  border-top: 1px solid var(--border);
  transition: background-color 0.2s ease, box-shadow 0.2s ease;
}
.cap:last-child { border-bottom: 1px solid var(--border); }
.cap:hover { background: var(--surface-page); box-shadow: inset 2px 0 0 var(--action-primary); }
.cap__num {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1rem;
  color: var(--action-primary);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}
.cap__clave {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.cap__titulo { margin-top: 4px; font-size: 1.0625rem; line-height: 1.3; }
/* Medida de lectura propia (la que tenía con el contenedor de 1200 px): con el contenedor más
   ancho, desde ~1460 px, la línea no pasa de unos 80 caracteres. */
.cap__texto { margin-top: 6px; color: var(--text-secondary); font-size: 0.9688rem; max-width: 62ch; }

/* ---------- 4. Pestañas ---------- */
.pestanas__lista {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
}
.no-js .pestanas__lista { display: none; }
.pestana {
  position: relative;
  min-height: 48px;
  padding: 12px 20px;
  background: none;
  border: 0;
  font: 600 1rem/1.2 var(--font-display);
  color: var(--text-secondary);
  cursor: pointer;
}
.pestana:hover { color: var(--brand-primary); }
.pestana[aria-selected="true"] { color: var(--action-primary); }
.pestana[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px; bottom: -1px;
  height: 3px;
  background: var(--action-primary);
  border-radius: 2px 2px 0 0;
}
.pestana--pacientes::before {
  content: "";
  display: inline-block;
  width: 10px; height: 10px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--accent-human);
  box-shadow: 0 0 0 1px var(--brand-primary);
  vertical-align: 0.05em;
}

.panel {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(28px, 4vw, 56px);
  padding-top: clamp(28px, 4vw, 48px);
  align-items: center;
}
.panel:focus-visible { outline-offset: 6px; }
html.js:not(.pestanas-listas):not([data-pestana-inicial="para-cirujanos"]) #para-cirujanos,
html.js:not(.pestanas-listas):not([data-pestana-inicial="para-patologos"]) #para-patologos,
html.js:not(.pestanas-listas):not([data-pestana-inicial="para-clinicas"]) #para-clinicas,
html.js:not(.pestanas-listas):not([data-pestana-inicial="para-pacientes"]) #para-pacientes { display: none; }
.no-js .panel + .panel { margin-top: 48px; border-top: 1px solid var(--border); }
.panel__texto { grid-column: 1 / span 7; }
.panel__figura {
  grid-column: 8 / span 5;
  padding: 16px;
  background-color: var(--white);
  background-image:
    linear-gradient(to right, rgba(16, 43, 70, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(16, 43, 70, 0.05) 1px, transparent 1px);
  background-size: 16px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-panel);
}
.panel__titulo { font-size: 1.125rem; line-height: 1.3; color: var(--text-secondary); font-weight: 600; }
.promesa {
  margin-top: 12px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.375rem, 1.05rem + 1.2vw, 1.875rem);
  line-height: 1.22;
  letter-spacing: -0.01em;
  max-width: 30ch;
}
.lista-check {
  display: grid;
  gap: 12px;
  margin-top: 24px;
  list-style: none;
  max-width: 58ch;
}
.lista-check li {
  position: relative;
  padding-left: 32px;
  color: var(--text-secondary);
}
.lista-check li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.15em;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--action-primary) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5.5 10.2l3 3 6-6.4' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 20px 20px no-repeat;
}
.panel__acciones { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

/* Esquemas de los paneles (ilustrativos) */
.esquema { width: 100%; height: auto; }
.esquema__lecho { fill: var(--action-primary); }
.esquema__cavidad { fill: none; stroke: var(--white); stroke-width: 10; stroke-linecap: round; }
.esquema__pieza { fill: var(--accent-innovation); }
.esquema__marca { fill: var(--brand-margin); stroke: var(--brand-primary); stroke-width: 2.5; }
.esquema__guia { fill: none; stroke: var(--brand-primary); stroke-width: 1.5; }
.esquema__txt { font: 600 13px var(--font-display); fill: var(--brand-primary); }
.esquema__txt--centro { text-anchor: middle; font-size: 12px; }
/* Póster del relato de Patólogos: el esquema se achica en celular, así que su texto va a 16 (queda
   sobre 12 px a 320 px de ancho). */
.esquema__txt--poster { font-size: 16px; }
.esquema__txt--tenue { fill: var(--text-secondary); }
.esquema__cavidad--fina { stroke-width: 6; }
.esquema__hoja { fill: none; stroke: var(--border-control); stroke-width: 1.5; stroke-linejoin: round; }
/* Póster del relato de Clínicas: el enlace entre equipos es continuo (un hecho) y el punteado
   queda solo para el marco de los objetivos. */
.esquema__sesion { fill: none; stroke: var(--brand-primary); stroke-width: 1.5; }
.esquema__ficha { fill: var(--white); stroke: var(--brand-primary); stroke-width: 1.25; }
.esquema__objetivos { fill: none; stroke: var(--brand-primary); stroke-width: 1.25; stroke-dasharray: 5 4; }
.panel__pie { margin-top: 10px; font-size: 0.8125rem; line-height: 1.45; color: var(--text-secondary); }
.esquema__red { fill: none; stroke: var(--border-control); stroke-width: 1.5; stroke-dasharray: 5 5; }
.esquema__nodo { fill: var(--brand-primary); }
.esquema__nodo--sec { fill: var(--action-primary); }
.esquema__enlace { fill: none; stroke: var(--brand-primary); stroke-width: 1.5; stroke-dasharray: 4 4; }

/* Paneles con relato animado para profesionales (2026-10-03: Cirujanos y Patólogos). Misma disposición
   que Pacientes (escenario en 7 de 12 columnas y los 4 pasos al lado; viñetas y botones debajo),
   sin melocotón: escenario blanco con filete (un visor, no una tarjeta de color) y el acento del
   público en el paso activo. --publico-acento y --publico-tinte cambian por público. */
.panel--publico { display: block; }
.publico-panel__intro .promesa { max-width: 34ch; }
/* La promesa de Clínicas es larga: con el tope de 34 caracteres tomaría seis líneas. */
.publico-panel__intro .promesa--larga { max-width: 52ch; }
.publico {
  --publico-acento: var(--action-primary);
  --publico-tinte: var(--action-tint);
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
  margin-top: clamp(20px, 3vw, 32px);
}
/* Patólogos: su protagonista es la pieza (violeta). El tinte es el violeta de marca aclarado, como
   --action-tint lo es del azul. */
/* Clínicas: no tiene un sólido protagonista; su acento es el azul profundo de la marca. */
.publico--clinicas {
  --publico-acento: var(--brand-primary);
  --publico-tinte: #ECEFF3;
}
.publico--patologos {
  --publico-acento: var(--accent-innovation);
  --publico-tinte: #F1EFFA;
}
.publico__visual { grid-column: 1 / span 7; display: grid; gap: 10px; align-content: start; }
.publico__pasos, .publico__nota { grid-column: 8 / span 5; }
.publico__pasos { display: grid; gap: 8px; list-style: none; }
@media (min-width: 1100px) {
  .publico { grid-template-rows: auto 1fr; row-gap: 14px; }
  .publico__visual { grid-row: 1 / span 2; }
  .publico__pasos { grid-row: 1; }
  .publico__nota { grid-row: 2; align-self: start; }
}
.publico__escenario {
  position: relative;
  aspect-ratio: 16 / 11;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 16px;
  overflow: hidden;
}
.publico__ir {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  width: 100%;
  padding: 12px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 12px;
  font: 400 1rem/1.5 var(--font-text);
  color: var(--brand-primary);
  text-align: left;
  cursor: pointer;
  transition: background-color 0.25s ease, border-color 0.25s ease;
}
.publico__ir:hover { background: var(--publico-tinte); }
/* Sin JavaScript, o si el módulo no llegó (el host es quien pone data-publico-modo), los pasos
   son solo texto: sin mano ni realce. */
.publico:not([data-publico-modo]) .publico__ir { cursor: default; }
.publico:not([data-publico-modo]) .publico__ir:hover { background: transparent; }
.publico__num {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border: 2px solid var(--brand-primary);
  border-radius: 50%;
  font: 800 0.9375rem/1 var(--font-display);
}
.publico__ir[aria-current="step"] { background: var(--white); border-color: var(--border); box-shadow: inset 4px 0 0 var(--publico-acento); }
.publico__ir[aria-current="step"] .publico__num { background: var(--brand-primary); color: var(--white); }
.publico__txt strong { font-weight: 700; }
.publico__nota { font-size: 0.8125rem; color: var(--text-secondary); }
.publico__nota p + p { margin-top: 6px; }
/* Viñetas, botones y aviso de investigación: bajo el relato, con un filete que los separa. */
.publico-panel__cierre {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
  margin-top: clamp(28px, 4vw, 44px);
  padding-top: clamp(24px, 3vw, 36px);
  border-top: 1px solid var(--border);
}
.publico-panel__cierre .lista-check { grid-column: 1 / span 7; margin-top: 0; }
.publico-panel__cta { grid-column: 8 / span 5; }
.publico-panel__cta .panel__acciones { margin-top: 0; }

/* Panel de pacientes. Guía v3 (p.8 y p.11): el melocotón es un acento puntual que
   «acompaña el mensaje humano sin dominar la composición». El panel va en melocotón
   aclarado y el tono pleno queda en el filete, el paso activo y los detalles. */
.panel--pacientes {
  display: block;
  margin-top: clamp(20px, 3vw, 32px);
  padding: clamp(24px, 4vw, 48px);
  background: var(--human-card);
  color: var(--brand-primary);
  border-top: 6px solid var(--accent-human);
  border-radius: var(--radius-panel);
}
.panel--pacientes .panel__titulo { color: var(--brand-primary); }
.pacientes { display: grid; gap: clamp(24px, 3vw, 40px); }
.pacientes__intro .promesa { max-width: 34ch; }

.relato {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
}
.relato__escenario {
  grid-column: 1 / span 7;
  aspect-ratio: 16 / 11;
  background: var(--human-tint);
  border-radius: 16px;
  overflow: hidden;
}
.no-js .relato__escenario { display: none; }
.relato__pasos, .relato__controles, .relato__nota { grid-column: 8 / span 5; }
.no-js .relato__pasos { grid-column: 1 / -1; }
.relato__pasos { display: grid; gap: 8px; list-style: none; }
/* relato-pacientes.js arma .relato__visual con el escenario, la leyenda y los
   controles (Pausar y Ver de nuevo), en ese orden: los controles quedan junto a lo
   que se mueve en cualquier ancho. En escritorio el visual ocupa dos filas y la
   columna derecha se apila sin huecos: pasos y nota. */
.relato__visual { grid-column: 1 / span 7; display: grid; gap: 10px; align-content: start; }
.relato__visual :is(.relato__escenario, .relato__controles) { grid-column: auto; grid-row: auto; }
@media (min-width: 1100px) {
  .relato { grid-template-rows: auto 1fr; row-gap: 14px; }
  .relato__visual, .relato > .relato__escenario { grid-row: 1 / span 2; }
  .relato__pasos { grid-row: 1; }
  .relato__nota { grid-row: 2; align-self: start; }
}
.relato__ir {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  width: 100%;
  padding: 12px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 12px;
  font: 400 1rem/1.5 var(--font-text);
  color: var(--brand-primary);
  text-align: left;
  cursor: pointer;
  transition: background-color 0.25s ease, border-color 0.25s ease;
}
.relato__ir:hover { background: rgba(232, 190, 166, 0.3); }
.relato__num {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border: 2px solid var(--brand-primary);
  border-radius: 50%;
  font: 800 0.9375rem/1 var(--font-display);
}
.relato__ir[aria-current="step"] { background: var(--white); border-color: var(--accent-human); box-shadow: inset 4px 0 0 var(--accent-human); }
.relato__ir[aria-current="step"] .relato__num { background: var(--brand-primary); color: var(--white); }
.relato__txt strong { font-weight: 700; }
.relato__controles { display: flex; gap: 16px; }
.relato__nota { font-size: 0.8125rem; }

.pacientes__tarjetas {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}
.tarjeta-humana {
  padding: 22px 24px;
  background: var(--white);
  border: 1px solid var(--accent-human);
  border-radius: 14px;
}
.tarjeta-humana h4 { font-size: 1.125rem; }
.tarjeta-humana p { margin-top: 8px; }
/* Glosario para pacientes (2026-09-29): tres preguntas en tarjetas como las de arriba; una columna
   en móvil. */
.glosario__titulo { font-size: 1.125rem; }
.glosario__lista {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 12px 0 0;
}
.glosario__item {
  padding: 18px 20px;
  background: var(--white);
  border: 1px solid var(--accent-human);
  border-radius: 14px;
}
.glosario__item dt { font-family: var(--font-display); font-weight: 700; color: var(--brand-primary); }
.glosario__item dd { margin: 6px 0 0; }
@media (max-width: 1099px) {
  .glosario__lista { grid-template-columns: minmax(0, 1fr); }
}
.pacientes__cierre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 24px;
  padding-top: 24px;
  border-top: 1px solid rgba(16, 43, 70, 0.25);
}
.sello {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  flex-basis: 100%;
}

/* ---------- Misión y visión (franja sin número entre «Para quién» y «Evidencia») ----------
   Reemplaza a .mision y .mision__texto. Textos oficiales completos (2026-09-27), con el mismo
   peso: misión (hoy) a la izquierda o arriba, visión (hacia dónde va) a la derecha o abajo.
   Bloque institucional en azul profundo (guía v3, p. 8). Un trazo cian de 2 px abre la franja,
   el mismo que abre las cifras de la serie FALP justo debajo. Rótulos: .eyebrow--oscuro.
   Sin movimiento. Contraste: blanco / azul profundo 14,4:1; cian / azul profundo 7,2:1. */
.mv { padding-block: clamp(56px, 7vw, 104px); }
.mv__rejilla {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  border-top: 2px solid var(--brand-margin);
}
.mv__bloque { padding-top: clamp(20px, 2.4vw, 28px); }
.mv__bloque + .mv__bloque {
  margin-top: clamp(28px, 4vw, 40px);
  border-top: 1px solid rgba(255, 255, 255, 0.18); /* decorativo */
}
.mv__texto {
  max-width: 38ch;
  font: 600 clamp(1.1875rem, 1rem + 0.7vw, 1.625rem)/1.4 var(--font-display);
  letter-spacing: -0.005em;
  color: var(--white);
}
/* Dos columnas desde el mismo corte en que desaparece la barra fija móvil. */
@media (min-width: 1000px) {
  .mv__rejilla { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mv__bloque:first-child { padding-right: clamp(32px, 4vw, 64px); }
  .mv__bloque + .mv__bloque {
    margin-top: 0;
    padding-left: clamp(32px, 4vw, 64px);
    border-top: 0;
    border-left: 1px solid rgba(255, 255, 255, 0.18);
  }
}

/* ---------- 5. Evidencia ---------- */
.evidencia {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  /* Entre columnas, el mismo espacio que .rejilla-2 (72 px en escritorio ancho): la columna derecha
     empieza en la misma línea vertical que la tarjeta del hero y que Problema, Preguntas y
     Contacto. Entre filas (apiladas, bajo 1100 px), el de siempre. */
  gap: clamp(28px, 4vw, 56px) clamp(32px, 5vw, 72px);
  align-items: start;
}
.serie {
  grid-column: 1 / span 5;
  padding: clamp(24px, 3vw, 36px);
  background: var(--brand-primary);
  color: var(--white);
  border-radius: var(--radius-panel);
  --focus: var(--brand-margin);
}
.serie__eyebrow {
  font: 700 0.8125rem/1.3 var(--font-display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brand-margin);
}
.serie h3 { margin-top: 12px; font-size: 1.375rem; line-height: 1.25; }
.serie__cifras {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin: 28px 0 0;
  padding-top: 20px;
  border-top: 2px solid var(--brand-margin);
}
/* La cifra va arriba y alineada entre columnas aunque un rótulo ocupe dos líneas. */
.serie__cifras div { display: flex; flex-direction: column; gap: 4px; }
.serie__cifras dd {
  order: -1;
  margin: 0;
  font: 800 clamp(2.5rem, 1.8rem + 2.5vw, 3.5rem)/1 var(--font-display);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.serie__cifras dt { font-size: 0.875rem; font-weight: 500; color: var(--on-dark-muted); }
.serie__pie { margin-top: 20px; font-size: 0.875rem; color: var(--on-dark-muted); }

.hitos { grid-column: 6 / span 7; list-style: none; }
.hito {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  column-gap: 24px;
  padding-block: 18px;
  border-top: 1px solid var(--border);
}
.hito:last-child { border-bottom: 1px solid var(--border); }
.hito__tipo {
  grid-row: span 2;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-secondary);
  padding-top: 4px;
}
.hito h3 { font-size: 1.0625rem; line-height: 1.35; }
.hito p:last-child { margin-top: 4px; color: var(--text-secondary); font-size: 0.9375rem; }

.logos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-top: clamp(40px, 5vw, 64px);
  list-style: none;
}
.logos li {
  display: grid;
  place-items: center;
  height: 96px;
  padding: 14px 18px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}
.logos img { max-height: 56px; max-width: 100%; width: auto; object-fit: contain; }
.nota-legal { margin-top: 12px; font-size: 0.8125rem; color: var(--text-secondary); }

/* ---------- 6. Simulador (sección oscura) ---------- */
/* --sim-3d es el centinela del relato en 3 actos: el host (simulador.js) solo lo enciende si esta
   hoja lo trae; con una hoja anterior en caché queda el dibujo plano con sus dos radios. */
.sim {
  --sim-3d: 1;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(28px, 4vw, 56px);
  row-gap: 12px;
  align-items: start;
}
.sim__escenario {
  grid-column: 1 / span 7;
  aspect-ratio: 16 / 10;
  background-color: var(--navy-deep);
  background-image:
    linear-gradient(to right, rgba(61, 200, 217, 0.07) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(61, 200, 217, 0.07) 1px, transparent 1px);
  background-size: 20px 20px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-panel);
  overflow: hidden;
}
.no-js .sim__escenario { display: none; }
.sim__panel { grid-column: 8 / span 5; display: grid; gap: 24px; }
.no-js .sim__panel { grid-column: 1 / -1; }
.sim__modo { margin: 0; padding: 0; border: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.sim__modo legend {
  width: 100%;
  margin-bottom: 10px;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-dark-muted);
}
.sim__modo label { position: relative; display: inline-flex; }
.sim__modo input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.sim__modo span {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 10px 18px;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 999px;
  font: 600 0.9375rem/1 var(--font-display);
  color: var(--white);
}
.sim__modo input:checked + span { background: var(--white); color: var(--brand-primary); border-color: var(--white); }
.sim__modo input:focus-visible + span { outline: 2px solid var(--brand-margin); outline-offset: 2px; }
.sim__explica h3 { font-size: 1.3125rem; line-height: 1.25; }
.sim__explica p { margin-top: 10px; color: var(--on-dark-muted); }
.sim__explica > div + div { margin-top: 24px; }
.sim__explica > div[hidden] + div { margin-top: 0; }
.no-js .sim__modo { display: none; }
.sim__panel .btn { justify-self: start; }
.sim__nota { margin-top: 20px; font-size: 0.8125rem; color: var(--on-dark-muted); max-width: 80ch; }

/* ---------- 7. Preguntas ---------- */
.faq { border-bottom: 1px solid var(--border); }
.faq__item { border-top: 1px solid var(--border); }
.faq__item summary {
  position: relative;
  display: block;
  padding: 20px 44px 20px 0;
  font: 600 1.0625rem/1.4 var(--font-display);
  color: var(--brand-primary);
  cursor: pointer;
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: "";
  position: absolute;
  right: 6px; top: 50%;
  width: 14px; height: 14px;
  margin-top: -7px;
  background:
    linear-gradient(var(--action-primary), var(--action-primary)) center / 14px 2px no-repeat,
    linear-gradient(var(--action-primary), var(--action-primary)) center / 2px 14px no-repeat;
  transition: transform 0.2s ease;
}
.faq__item[open] summary::after { transform: rotate(45deg); }
.faq__item summary:hover { color: var(--action-primary); }
.faq__item p { padding: 0 44px 22px 0; color: var(--text-secondary); max-width: 65ch; }

/* ---------- 8. Contacto y formulario ---------- */
.rejilla-contacto {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.contacto__info { grid-column: 1 / span 5; }
.form-tarjeta { grid-column: 6 / span 7; }

.pasos { display: grid; gap: 16px; margin-top: 28px; list-style: none; counter-reset: paso; }
.pasos li {
  position: relative;
  padding-left: 44px;
  color: var(--text-secondary);
  counter-increment: paso;
}
.pasos li::before {
  content: counter(paso);
  position: absolute;
  left: 0; top: -2px;
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--action-primary);
  color: var(--white);
  font: 800 0.875rem/1 var(--font-display);
}
.pasos strong { color: var(--brand-primary); font-weight: 600; }

.canales { margin-top: 32px; padding-top: 24px; border-top: 1px solid var(--border); }
.canales__titulo { font-family: var(--font-display); font-weight: 700; }
.canales ul { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 10px; list-style: none; }
.canales a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  font-weight: 500;
}
.canales__icono { width: 24px; height: 24px; flex: none; }
.leyenda-legal {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--text-secondary);
}

.form-tarjeta {
  padding: clamp(20px, 3vw, 36px);
  background: var(--surface-page);
  border: 1px solid var(--border);
  border-radius: 16px;
}
/* .form__resto: los campos que siguen al perfil (formulario.js los muestra al elegirlo). */
.form, .form__resto { display: grid; gap: 20px; }
.form__titulo { font-size: 1.375rem; line-height: 1.25; }
.form__titulo:focus { outline: none; }
.form__titulo:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }
.form__interes {
  padding: 10px 14px;
  background: var(--action-tint);
  border-left: 3px solid var(--action-primary);
  border-radius: 4px;
  font-size: 0.9375rem;
}
.form__req { font-size: 0.8125rem; color: var(--text-secondary); margin-top: -8px; }

.campo { display: grid; gap: 6px; margin: 0; padding: 0; border: 0; min-width: 0; }
.campo > label, .campo > legend {
  font-weight: 500;
  font-size: 0.9375rem;
  color: var(--brand-primary);
  padding: 0;
}
.campo > legend { margin-bottom: 6px; }
.opcional { font-weight: 400; color: var(--text-secondary); }
.no-js label[for="f-comentario"] .opcional { display: none; }
.campo input[type="text"],
.campo input[type="email"],
.campo select,
.campo textarea {
  width: 100%;
  min-height: 48px;
  padding: 11px 14px;
  background: var(--white);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-control);
  font: 400 1rem/1.4 var(--font-text);
  color: var(--brand-primary);
}
.campo textarea { min-height: 112px; resize: vertical; }
.campo select {
  appearance: none;
  padding-right: 44px;
  background: var(--white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4' fill='none' stroke='%23102B46' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") right 14px center / 16px no-repeat;
}
.campo input:focus-visible,
.campo select:focus-visible,
.campo textarea:focus-visible {
  outline: 2px solid var(--action-primary);
  outline-offset: 1px;
  border-color: var(--action-primary);
}
.campo input[aria-invalid="true"],
.campo select[aria-invalid="true"],
.campo textarea[aria-invalid="true"] { border-color: var(--state-error); border-width: 2px; }
.campo__ayuda { font-size: 0.8125rem; color: var(--text-secondary); }
.campo__error {
  display: flex;
  gap: 6px;
  align-items: flex-start;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--state-error);
}
.campo__error::before { content: "Error:"; font-weight: 700; }

.perfiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.perfil {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 52px;
  padding: 10px 14px;
  background: var(--white);
  border: 1px solid var(--border-control);
  border-radius: 10px;
  font-size: 0.9375rem;
  line-height: 1.3;
  cursor: pointer;
}
.perfil input { width: 18px; height: 18px; margin: 0; flex: none; accent-color: var(--action-primary); }
.perfil:has(input:checked) { border-color: var(--action-primary); box-shadow: inset 0 0 0 1px var(--action-primary); background: var(--action-tint); }
.perfil:has(input:focus-visible) { outline: 2px solid var(--action-primary); outline-offset: 2px; }
.campo--perfil[aria-invalid="true"] .perfil { border-color: var(--state-error); }

.campo--check { grid-template-columns: 22px minmax(0, 1fr); column-gap: 10px; align-items: start; }
.campo--check input { width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--action-primary); }
.campo--check label { font-weight: 400; font-size: 0.9375rem; }
.campo--check .campo__error { grid-column: 1 / -1; }

.aviso-paciente {
  padding: 12px 14px;
  background: var(--accent-human);
  border-radius: 8px;
  color: var(--brand-primary);
  font-size: 0.9375rem;
}
/* Aviso breve de privacidad entre la casilla y el botón (2026-09-29): quién trata los datos, para
   qué y cómo pedir acceso, corrección o eliminación. formulario.js lo pasa a «tú» con pacientes. */
.aviso-privacidad { font-size: 0.8125rem; line-height: 1.45; color: var(--text-secondary); }

.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }

.form__estado {
  display: grid;
  gap: 12px;
  padding: 24px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 4px solid var(--action-primary);
  border-radius: var(--radius-card);
}
.form__estado:focus { outline: none; }
.form__estado:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.form__estado h3 { font-size: 1.25rem; }
.form__estado--error { border-left-color: var(--state-error); }
.form__estado--incierto { border-left-color: var(--brand-primary); }
.form__estado-acciones { display: flex; flex-wrap: wrap; gap: 12px; }

/* ---------- Pie ---------- */
.pie {
  --focus: var(--brand-margin);
  padding-block: clamp(48px, 6vw, 80px);
  background: var(--brand-primary);
  color: var(--on-dark-muted);
  font-size: 0.875rem;
}
.pie a { color: var(--white); }
.pie a:hover { color: var(--brand-margin); }
.pie__rejilla {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 32px;
}
.pie__marca { grid-column: 1 / span 3; }
.pie__legal { grid-column: 4 / span 5; display: grid; gap: 12px; }
.pie__datos { grid-column: 9 / span 4; display: grid; gap: 8px; align-content: start; }
.placa-logo {
  display: inline-block;
  padding: 14px 18px;
  background: var(--surface-page);
  border-radius: var(--radius-card);
}
.placa-logo img { width: 160px; height: auto; }
.pie__marca p { margin-top: 14px; }
.pie__creditos { font-size: 0.75rem; }

/* ---------- Barra fija en móvil ---------- */
.barra-movil {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom));
  background: var(--white);
  border-top: 1px solid var(--border);
}
.barra-movil .btn { flex: 1; }
@media (min-width: 1000px) {
  .barra-movil { display: none !important; }
}

/* ---------- Adaptación: tableta ---------- */
@media (max-width: 1099px) {
  .hero__texto, .visor { grid-column: 1 / -1; }
  /* Título en 3 líneas desde tableta: «Cirugía oncológica de precisión: / trazabilidad 3D de
     márgenes / en tiempo real.» (en móvil, por frases). */
  .hero__titulo { max-width: 15em; }
  .hero__titulo .acento { display: block; }
  .visor__lienzo { aspect-ratio: 4 / 3; }
  /* En la composición apilada el fondo animado acompaña a la escena, debajo del texto: a todo el
     ancho, desde un poco antes del lienzo (ver «Fondo animado» en «Hero»). */
  .rejilla-2 > .seccion__cabeza,
  .rejilla-2 > :last-child { grid-column: 1 / -1; }
  .problema > .seccion__cabeza,
  .problema > .problema__datos,
  .problema > .argumento { grid-column: 1 / -1; grid-row: auto; }
  .tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .caps { grid-column: 1 / -1; }
  .panel__texto, .panel__figura { grid-column: 1 / -1; }
  .panel__figura { max-width: 440px; }
  .relato__visual, .relato__escenario, .relato__pasos, .relato__controles, .relato__nota { grid-column: 1 / -1; }
  .publico__visual, .publico__pasos, .publico__nota,
  .publico-panel__cierre .lista-check, .publico-panel__cta { grid-column: 1 / -1; }
  /* En tableta el escenario no pasa de 760 px de ancho: a 16/11 llenaría la pantalla entera. */
  .publico__visual { max-width: 760px; }
  .serie, .hitos { grid-column: 1 / -1; }
  .sim__escenario, .sim__panel { grid-column: 1 / -1; }
  .contacto__info, .form-tarjeta { grid-column: 1 / -1; }
  .pie__marca { grid-column: 1 / -1; }
  .pie__legal { grid-column: 1 / span 7; }
  .pie__datos { grid-column: 8 / span 5; }
}

/* Barra de la fila de respaldos: oculta al tacto (el dedo la desliza); con mouse se ve, para poder
   correrla. */
@media (max-width: 699px) and (pointer: coarse) {
  .respaldos__ventana { scrollbar-width: none; }
  .respaldos__ventana::-webkit-scrollbar { display: none; }
}

/* ---------- Adaptación: móvil ---------- */
@media (max-width: 699px) {
  .hero__rejilla, .rejilla-2, .panel, .evidencia, .sim, .relato,
  .publico, .publico-panel__cierre,
  .rejilla-contacto, .pie__rejilla { grid-template-columns: minmax(0, 1fr); }
  .hero__acciones .btn { width: 100%; }
  .hero__paciente { padding-block: 12px; }
  .visor__lienzo { aspect-ratio: 1 / 1; }
  /* Respaldos en una sola fila: quieta y deslizable con el dedo (sin JavaScript o con movimiento
     reducido) o la cinta de respaldos.js (ver «Módulo: franja de respaldos»). La ventana llega a
     los bordes de la pantalla (el margen negativo es el relleno del contenedor: no desborda) y no
     muestra barra, así la fila y la cinta miden lo mismo. Cada rótulo va delante de su grupo. */
  .respaldos__ventana {
    margin: -4px calc(-1 * var(--gutter));   /* 4 px arriba y abajo para el anillo de foco */
    padding: 4px var(--gutter);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--gutter);
  }
  .respaldos__pista { display: flex; width: max-content; }
  .respaldos__juego { display: flex; align-items: center; column-gap: 24px; padding-inline-end: 24px; }
  .respaldos__grupo { display: flex; align-items: center; column-gap: 12px; }
  .respaldos__rotulo { flex: none; width: 8rem; margin: 0; font-size: 0.8125rem; text-wrap: balance; }
  .confianza { display: flex; gap: 12px; }
  .confianza__item { flex: none; width: 10rem; scroll-snap-align: start; }
  .confianza__enlace { gap: 8px; padding: 8px 4px; }
  .confianza__marca { height: 44px; }
  .confianza__logo--falp { --alto-logo: 44px; }
  .confianza__logo--slap { --alto-logo: 40px; }
  .confianza__logo--3ie { --alto-logo: 32px; }
  .confianza__logo--usm { --alto-logo: 38px; }
  .confianza__logo--suc { --alto-logo: 28px; }
  .confianza__logo--ahns { --alto-logo: 18px; }
  .confianza__logo--babson { --alto-logo: 15px; }
  .confianza__txt { font-size: 0.875rem; }
  .cifra { grid-template-columns: 1fr; }
  .cifra__valor { grid-row: auto; }
  .tarjetas { grid-template-columns: 1fr; }
  .pestanas__lista {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    border-bottom: 0;
  }
  .pestana { border: 1px solid var(--border-control); border-radius: var(--radius-control); background: var(--white); }
  .pestana[aria-selected="true"] { background: var(--action-primary); color: var(--white); border-color: var(--action-primary); }
  .pestana[aria-selected="true"]::after { display: none; }
  .panel__acciones .btn { width: 100%; }
  .pacientes__tarjetas { grid-template-columns: 1fr; }
  .hito { grid-template-columns: 1fr; }
  .hito__tipo { grid-row: auto; padding-top: 0; margin-bottom: 4px; }
  .serie__cifras { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .perfiles { grid-template-columns: 1fr; }
  .pie__legal, .pie__datos { grid-column: 1 / -1; }
}

/* ---------- Movimiento reducido ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ==========================================================================
   Módulo: Relato de los 4 pasos para pacientes (relato-pacientes.js con pasos3d.js)
   ========================================================================== */
/* El reproductor pone su lienzo WebGL (transparente) sobre el melocotón aclarado del
   escenario. Sin WebGL 2 o con ?sin3d=1 (.relato--sin3d) quedan los pasos como texto,
   igual que sin JavaScript. */
.relato__escenario[data-relato-escenario] { position: relative; }
.relato__escenario canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.relato--sin3d .relato__visual { display: none; }
@media (max-width: 699px) {
  .relato__escenario { aspect-ratio: 5 / 4; }
}
/* Apaisada y baja: el escenario cabe en el alto útil de la ventana. */
@media (max-width: 1099px) and (max-height: 560px) and (orientation: landscape) {
  .relato__escenario {
    aspect-ratio: auto;
    height: clamp(200px, calc(100vh - 150px), 420px);
    height: clamp(200px, calc(100svh - 150px), 420px);
  }
}
.relato--sin3d :is(.relato__pasos, .relato__nota) { grid-column: 1 / -1; grid-row: auto; }

/* Leyenda de colores: la pone el JS dentro de .relato__visual, bajo el
   escenario; la separación la da el gap de ese contenedor (estilos.css). */
.rl-leyenda {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 20px;
  margin: 0;
  padding: 0;
  list-style: none;
  font: 500 0.8125rem/1.3 var(--font-text);
  color: var(--brand-primary);
}
.rl-leyenda li { display: inline-flex; align-items: center; gap: 8px; }
.rl-muestra {
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  box-shadow: 0 0 0 1.5px var(--brand-primary);
}
.rl-muestra--pieza { background: var(--accent-innovation); }
.rl-muestra--lecho { background: var(--action-primary); }
.rl-muestra--borde { height: 5px; border-radius: 3px; background: var(--brand-margin); }
/* Leyenda por paso (data-paso lo pone relato-pacientes.js), como en la tarjeta: «Pieza
   retirada» y «Zona operada» atenuadas hasta el paso 3 y «Borde a revisar» hasta el 2. La
   muestra baja al 45 %; el texto, a un gris que sigue en 4,9:1 sobre el melocotón claro. */
.rl-leyenda li { transition: color 0.3s ease; }
.rl-muestra { transition: opacity 0.3s ease; }
.relato[data-paso="1"] .rl-leyenda li,
.relato[data-paso="2"] .rl-leyenda li:not(:last-child) { color: #5B6B7C; }
.relato[data-paso="1"] .rl-muestra,
.relato[data-paso="2"] .rl-leyenda li:not(:last-child) .rl-muestra { opacity: 0.45; }

/* Controles: blanco táctil de 44 px. */
.relato__controles { flex-wrap: wrap; }
.relato__controles .btn-texto { min-height: 44px; }

/* ==========================================================================
   Módulo: Relato por público (relato-publicos.js con publicos3d.js, cirujanos3d.js y patologos3d.js)
   ========================================================================== */
/* El reproductor pone su capa (.publico3d-capa: el lienzo WebGL transparente y, encima, las notas
   en HTML y SVG) dentro del escenario blanco. Mientras carga el 3D el escenario queda vacío: el
   esquema fijo trae la marca y adelantaría el final. Sin JavaScript, sin WebGL 2, con ?sin3d=1 o
   con el contexto perdido (.publico--sin3d) queda ese esquema como póster, con su leyenda (hay
   cian), y los pasos como texto. */
.js .publico:not(.publico--sin3d) .publico__poster { display: none; }
@media (max-width: 699px) {
  .publico__escenario { aspect-ratio: 1 / 1; }
}
/* Patólogos muestra tres lugares (la pieza, la vista de pabellón y el reporte): en celular vertical
   su escenario es algo más alto, para que la pieza no se achique al ceder lugar. */
@media (max-width: 699px) and (orientation: portrait) {
  .publico--patologos .publico__escenario { aspect-ratio: 5 / 6; }
  /* Sin pasar del alto útil (cabecera, barra fija de abajo y el rótulo del paso: 190 px), con un
     piso de 320 px de ancho: en ventanas verticales poco altas (plegables, ventanas angostas). */
  .publico--patologos .publico__visual {
    max-width: max(320px, calc((100vh - 190px) * 5 / 6));
    max-width: max(320px, calc((100svh - 190px) * 5 / 6));
  }
  /* Clínicas apila la fila de equipos, el reporte, los objetivos y la oferta: 4/5, con el mismo
     tope por alto útil. */
  .publico--clinicas .publico__escenario { aspect-ratio: 4 / 5; }
  .publico--clinicas .publico__visual {
    max-width: max(320px, calc((100vh - 190px) * 4 / 5));
    max-width: max(320px, calc((100svh - 190px) * 4 / 5));
  }
}
/* Bajo 340 px de ancho las líneas de los objetivos se parten: el escenario de Clínicas pasa a 3/4,
   para que los dos equipos no queden mínimos. */
@media (max-width: 339px) and (orientation: portrait) {
  .publico--clinicas .publico__escenario { aspect-ratio: 3 / 4; }
}
/* Apaisada y baja: el escenario busca caber en el alto útil de la ventana. No baja de 240 px: con
   menos, la marca del lecho quedaría bajo los 14 px. Bajo 1000 px de ancho se descuenta además la
   barra fija de abajo, que en esta pestaña sigue a la vista (190 px: cabecera, barra y el rótulo
   del paso). Con menos de unos 410 px de alto manda el piso de 240 px: el escenario cabe entre la
   cabecera y la barra, pero no junto con su rótulo. */
@media (max-width: 1099px) and (max-height: 560px) and (orientation: landscape) {
  .publico__escenario {
    aspect-ratio: auto;
    height: clamp(240px, calc(100vh - 120px), 420px);
    height: clamp(240px, calc(100svh - 120px), 420px);
  }
}
@media (max-width: 999px) and (max-height: 560px) and (orientation: landscape) {
  .publico__escenario {
    height: clamp(240px, calc(100vh - 190px), 420px);
    height: clamp(240px, calc(100svh - 190px), 420px);
  }
}
/* Patólogos, apaisado, bajo y muy angosto (zoom alto, ventanas chicas): en menos de unos 460 px de
   ancho y 240 de alto no caben sus tres lugares; el escenario pasa a ser vertical, como en celular
   (la escena los apila). Queda más alto que la ventana: se ve desplazando. */
@media (max-width: 519px) and (max-height: 560px) and (orientation: landscape) {
  .publico--patologos .publico__escenario { height: auto; aspect-ratio: 5 / 6; }
}
/* Clínicas, lo mismo, desde antes: bajo 600 px de ancho sus dos columnas no caben en 240 px de
   alto. Y bajo 340 px, 3/4, como en vertical. */
@media (max-width: 599px) and (max-height: 560px) and (orientation: landscape) {
  .publico--clinicas .publico__escenario { height: auto; aspect-ratio: 4 / 5; }
}
@media (max-width: 339px) and (max-height: 560px) and (orientation: landscape) {
  .publico--clinicas .publico__escenario { aspect-ratio: 3 / 4; }
}
/* Entre 600 y 639 px de ancho las dos columnas caben solo si el escenario pasa de unos 300 px de
   alto: con la ventana bajo 490 px (zoom alto), también vertical. */
@media (min-width: 600px) and (max-width: 639px) and (max-height: 489px) and (orientation: landscape) {
  .publico--clinicas .publico__escenario { height: auto; aspect-ratio: 4 / 5; }
}
/* Tableta apaisada (más de 560 px de alto): el escenario 16/11 no pasa del alto útil (bajo
   1000 px de ancho, descontada también la barra fija). */
@media (min-width: 700px) and (max-width: 1099px) and (min-height: 561px) {
  .publico__visual {
    max-width: min(760px, calc((100vh - 150px) * 16 / 11));
    max-width: min(760px, calc((100svh - 150px) * 16 / 11));
  }
}
@media (min-width: 700px) and (max-width: 999px) and (min-height: 561px) {
  .publico__visual {
    max-width: min(760px, calc((100vh - 190px) * 16 / 11));
    max-width: min(760px, calc((100svh - 190px) * 16 / 11));
  }
}
.publico--sin3d .publico__escenario,
.no-js .publico__escenario {
  aspect-ratio: auto;
  height: auto;
  max-width: 440px;
  padding: 16px;
}
.publico--sin3d .publico3d-capa { display: none; }

/* La capa aparece con un fundido corto en su primer cuadro. Durante un salto entre pasos el
   reproductor manda la opacidad en línea, sin transición. */
.publico3d-capa { position: absolute; inset: 0; opacity: 0; transition: opacity 0.3s ease; }
.publico--listo .publico3d-capa { opacity: 1; }
/* Si la escena retoma avanzada (al volver a la pestaña), aparece de una vez: ya puede haber cian a
   la vista, y el cian no cambia de opacidad. */
.publico--retoma .publico3d-capa { transition: none; }
.publico3d-capa canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.publico3d-notas { position: absolute; inset: 0; width: 100%; height: 100%; overflow: hidden; pointer-events: none; }
/* Contorno de la pieza superpuesta mientras es translúcida: blanco frío sobre el azul del lecho. */
.publico3d-contorno { fill: none; stroke: var(--surface-page); stroke-width: 1.5; stroke-linejoin: round; }
/* Pico de la placa a la marca: blanco con funda azul profundo (se lee sobre el lecho y sobre el
   escenario). */
.publico3d-pico-funda { stroke: var(--brand-primary); stroke-width: 3.5; stroke-linecap: round; }
.publico3d-pico { stroke: var(--white); stroke-width: 1.5; stroke-linecap: round; }
/* Placas: las del hero (blancas, borde y texto en azul profundo). El cian nunca es texto. */
.publico3d-placa {
  position: absolute;
  left: 0; top: 0;
  display: flex;
  align-items: center;
  height: 26px;
  padding: 0 10px;
  background: var(--white);
  border: 1.25px solid var(--brand-primary);
  border-radius: 13px;
  font: 700 0.8125rem/1 var(--font-display);
  color: var(--brand-primary);
  white-space: nowrap;
  pointer-events: none;
}
.publico3d-capa--compacta .publico3d-placa { height: 22px; padding: 0 8px; border-radius: 11px; font-size: 0.75rem; }

/* Notas de Patólogos (patologos3d.js). Las vistas «Pabellón» y «Reporte» son trazos finos sobre el
   escenario blanco, sin tarjetas ni rellenos: el marco de pabellón rodea el recorte del lecho (la
   tapa blanca cubre lo que el recorte, recto, deja fuera de sus esquinas redondas) y la hoja del
   reporte lleva la esquina doblada y barras en vez de texto. Cada vista aparece bajo un velo blanco
   que se retira. */
.publico3d-velo, .publico3d-tapa { fill: var(--white); }
.publico3d-tapa { fill-rule: evenodd; }
.publico3d-marco, .publico3d-hoja { fill: none; stroke: var(--border-control); stroke-width: 1.25; stroke-linejoin: round; }
.publico3d-doblez { fill: var(--surface-page); stroke: var(--border-control); stroke-width: 1.25; stroke-linejoin: round; }
.publico3d-barra { fill: var(--border); }
/* Rótulo de cada vista, bajo ella. */
.publico3d-rotulo {
  position: absolute;
  left: 0; top: 0;
  font: 600 0.75rem/16px var(--font-display);
  color: var(--text-secondary);
  white-space: nowrap;
  pointer-events: none;
}
/* Descripción que el profesional escribe junto a la píldora: texto simple, con el cursor de texto
   solo mientras se escribe. */
.publico3d-detalle {
  position: absolute;
  left: 0; top: 0;
  display: flex;
  align-items: center;
  height: 26px;
  font: 500 0.8125rem/1 var(--font-text);
  color: var(--brand-primary);
  white-space: nowrap;
  pointer-events: none;
}
.publico3d-detalle--escribe::after {
  content: "";
  width: 1.5px;
  height: 1.15em;
  margin-left: 1.5px;
  background: var(--brand-primary);
}
.publico3d-capa--compacta .publico3d-detalle { height: 22px; font-size: 0.75rem; }
/* Cursor: la flecha de puntero, blanca con filete azul profundo; el anillo marca que presiona. */
.publico3d-cursor {
  position: absolute;
  left: 0; top: 0;
  width: 40px;
  height: 48px;
  overflow: visible;
  pointer-events: none;
}
.publico3d-cursor__flecha { fill: var(--white); stroke: var(--brand-primary); stroke-width: 1.5; stroke-linejoin: round; }
.publico3d-cursor__pulso { fill: none; stroke: var(--brand-primary); stroke-width: 1.5; }

/* Notas de Clínicas (clinicas3d.js). Tres formas de dibujar, una por tipo de afirmación:
   - hecho: línea continua azul profundo (el enlace de sesión, su nodo y el hilo al reporte) y ficha
     de borde continuo azul profundo;
   - objetivo: solo texto gris, dentro de un marco punteado que lleva su rótulo. El punteado no se
     usa en ninguna otra parte de la escena;
   - oferta: fichas de borde gris, sin línea que las una a nada.
   La letra va en px fijos: el escenario es decorativo (aria-hidden) y el texto real son los pasos. */
.publico3d-enlace { stroke: var(--brand-primary); stroke-width: 1.5; stroke-linecap: round; }
.publico3d-nodo { fill: var(--brand-primary); }
.publico--clinicas .publico3d-placa { font-size: 13px; }
.publico--clinicas .publico3d-rotulo { font-size: 12px; }
.publico3d-rotulo--sesion { color: var(--brand-primary); }
.publico3d-ficha {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 10px;
  background: var(--white);
  border: 1.25px solid var(--brand-primary);
  border-radius: 6px;
  font: 600 13px/1 var(--font-display);
  color: var(--brand-primary);
  white-space: nowrap;
  pointer-events: none;
}
.publico3d-capa > .publico3d-ficha { position: absolute; left: 0; top: 0; }
/* La oferta no lleva la letra de los hechos: Inter 500, como los objetivos (Manrope V5 solo tiene
   600, 700 y 800). */
.publico3d-ficha--oferta { border: 1px solid var(--border-control); font-family: var(--font-text); font-weight: 500; }
.publico3d-bloque {
  position: absolute;
  left: 0; top: 0;
  display: grid;
  gap: 10px;
  justify-items: center;
  pointer-events: none;
}
.publico3d-objetivos {
  box-sizing: border-box;
  width: 100%;
  padding: 8px 12px 10px;
  border: 1.25px dashed var(--brand-primary);
  border-radius: 10px;
  text-align: center;
}
.publico3d-objetivos__rotulo { font: 600 12px/16px var(--font-display); color: var(--brand-primary); }
/* Un objetivo por renglón, a todo ancho: dos en un mismo renglón se leerían como una sola frase. */
.publico3d-objetivos__lineas { display: flex; flex-direction: column; align-items: center; gap: 2px; margin-top: 4px; }
.publico3d-objetivo { font: 500 13px/18px var(--font-text); color: var(--text-secondary); }
.publico3d-oferta { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 8px 22px; }
.publico3d-oferta__fila { display: inline-flex; align-items: center; gap: 7px; }
.publico3d-oferta__sigue { font: 500 13px/1 var(--font-text); color: var(--text-secondary); }
.publico--clinicas .publico3d-capa--compacta .publico3d-placa { font-size: 12px; }
.publico3d-capa--compacta .publico3d-ficha { height: 22px; padding: 0 8px; font-size: 12px; }
.publico3d-capa--compacta .publico3d-bloque { gap: 8px; }
.publico3d-capa--compacta .publico3d-objetivos { padding: 6px 8px 8px; }
.publico3d-capa--compacta .publico3d-objetivo { font-size: 12px; line-height: 16px; }
.publico3d-capa--compacta .publico3d-oferta { gap: 6px 14px; }

/* Título del paso activo pegado al escenario: en una columna los pasos quedan lejos del dibujo. */
.publico__rotulo {
  display: none;
  min-height: 1.4em;
  font: 700 0.9375rem/1.4 var(--font-display);
  color: var(--brand-primary);
}
@media (max-width: 1099px) {
  .js .publico:not(.publico--sin3d) .publico__rotulo { display: block; }
}
/* El título más largo de Patólogos («4 de 4 · Documente el hallazgo en contexto.») toma dos líneas
   bajo 344 px de ancho (o con la letra base agrandada: por eso va en em). Se reservan las dos
   desde el comienzo, para que al llegar al paso 4 no empuje lo que sigue. */
@media (max-width: 21.4375em) {
  .publico--patologos .publico__rotulo { min-height: 2.8em; }
}
/* El de Clínicas («2 de 4 · Lleve el caso al comité tumoral.») es más corto: se parte bajo 312 px. */
@media (max-width: 19.5em) {
  .publico--clinicas .publico__rotulo { min-height: 2.8em; }
}

/* Leyenda: lecho y pieza con muestra cuadrada; la marca, un disco cian con aro azul profundo
   (como en el escenario: el cian nunca solo). En Cirujanos, sin la entrada de la pieza cuando
   queda el póster (su póster no la dibuja; el de Patólogos sí). */
.publico__leyenda {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 20px;
  margin: 0;
  padding: 0;
  list-style: none;
  font: 500 0.8125rem/1.3 var(--font-text);
  color: var(--brand-primary);
}
.publico__leyenda li { display: inline-flex; align-items: center; gap: 8px; }
.publico__muestra {
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  box-shadow: 0 0 0 1.5px var(--brand-primary);
}
.publico__muestra--lecho { background: var(--action-primary); }
.publico__muestra--pieza { background: var(--accent-innovation); }
/* Objetivo (Clínicas): hueca y de borde punteado, como su marco en el escenario. */
.publico__muestra--objetivo { background: transparent; box-shadow: none; border: 1.5px dashed var(--brand-primary); }
.publico__muestra--marca {
  width: 11px;
  height: 11px;
  margin: 0 2px;
  border-radius: 50%;
  background: var(--brand-margin);
  box-shadow: 0 0 0 2.5px var(--brand-primary);
}
.publico--sin3d .publico__leyenda-pieza,
.no-js .publico__leyenda-pieza { display: none; }

/* Controles: blanco táctil de 44 px. Reservan su alto desde el comienzo (Cirujanos es la pestaña
   que se ve al llegar): aparecen con el primer cuadro sin empujar lo que sigue. */
.publico__controles { display: flex; flex-wrap: wrap; gap: 16px; }
.publico__controles .btn-texto { min-height: 44px; }
/* El conmutador de pausa lleva un icono de ancho fijo: dos barras mientras corre y un triángulo
   cuando está en pausa (su nombre no cambia: el estado lo dice aria-pressed). Así la pausa se nota
   a la vista sin cambiar el ancho del botón: la fila no se parte ni empuja lo que sigue. */
.publico__controles [aria-pressed]::before {
  content: "";
  display: inline-block;
  box-sizing: border-box;
  width: 0.6em;
  height: 0.7em;
  margin-right: 0.5em;
  border: solid currentColor;
  border-width: 0 0.2em;
}
.publico__controles [aria-pressed="true"] { color: var(--action-primary); }
.publico__controles [aria-pressed="true"]::before {
  border-color: transparent transparent transparent currentColor;
  border-width: 0.35em 0 0.35em 0.6em;
}
.js .publico:not(.publico--listo) .publico__controles { visibility: hidden; }
.publico--sin3d .publico__controles,
.no-js .publico__controles { display: none; }

/* Alto contraste: el escenario y las muestras conservan sus colores (son el dibujo y su clave), y
   el paso activo se distingue por el borde cuando el sistema sustituye los rellenos. */
@media (forced-colors: active) {
  .publico__escenario { forced-color-adjust: none; background: #FFFFFF; }
  .publico__muestra { forced-color-adjust: none; }
  .publico__muestra--objetivo { border-color: CanvasText; }
  .publico__ir[aria-current="step"] { border: 4px double ButtonText; }
}

/* ==========================================================================
   Módulo: Simulador (simulador.js)
   ========================================================================== */
/* ==========================================================================
   simulador.css — sección 6 (#simulador), esquema que arma simulador.js
   Se fusiona en estilos.css. Sobre el escenario azul noche solo van blanco,
   cian, violeta, azul digital y azul profundo; el texto, blanco o cian.
   ========================================================================== */

/* La disposición estrecha apila pieza y lecho: el escenario se alarga para
   que el texto del SVG no baje de 12 px. Coincide con su viewBox 320 × 484. */
.sim__escenario[data-sim-disposicion="estrecho"] { aspect-ratio: 320 / 484; }
/* Antes de que corra el módulo, los teléfonos ya reservan ese alto. */
@media (max-width: 560px) {
  .js .sim__escenario:not([data-sim-disposicion]) { aspect-ratio: 320 / 484; }
}

.sim-svg {
  --curva: cubic-bezier(0.65, 0, 0.35, 1);
  --salida: cubic-bezier(0.22, 1, 0.36, 1);
  --paso: 24ms;
  display: block;
  width: 100%;
  height: 100%;
}

/* ---------- Anatomía ---------- */
.sim-lecho {
  fill: var(--action-primary);
  stroke: var(--white);
  stroke-opacity: 0.5;
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
}
.sim-cavidad { fill: var(--navy-deep); fill-opacity: 0.42; }
.sim-cavidad-borde,
.sim-pieza {
  stroke: var(--white);
  stroke-opacity: 0.7;
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
}
.sim-cavidad-borde { fill: none; stroke-opacity: 0.6; }
.sim-pieza { fill: var(--accent-innovation); }
.sim-contorno {
  fill: none;
  stroke: var(--white);
  stroke-opacity: 0.18;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* ---------- Marcas ---------- */
.sim-punto { fill: var(--brand-margin); stroke: var(--brand-primary); stroke-width: 2.5; }
.sim-marca-anillo { fill: none; stroke: var(--white); stroke-width: 1.5; }
.sim-sitio { fill: none; stroke: var(--white); stroke-width: 1.5; stroke-dasharray: 3.3 2.2; }
.sim-sitio-centro { fill: var(--white); }
.sim-reticula { fill: none; stroke: var(--brand-margin); stroke-width: 2; stroke-linecap: round; }
.sim-radio {
  fill: none;
  stroke: var(--white);
  stroke-opacity: 0.8;
  stroke-width: 1.25;
  stroke-dasharray: 2 4;
  stroke-linecap: round;
}
.sim-intento circle { fill: none; stroke: var(--white); stroke-width: 1.75; }
.sim-hilo {
  fill: none;
  stroke: var(--white);
  stroke-opacity: 0.5;
  stroke-width: 1.5;
  stroke-dasharray: 0.1 5;
  stroke-linecap: round;
}
.sim-guia { fill: none; stroke: var(--white); stroke-opacity: 0.5; stroke-width: 1; }
.sim-vinculo {
  fill: none;
  stroke: var(--brand-margin);
  stroke-width: 2;
  stroke-dasharray: 6 5;
  stroke-linecap: round;
}
.sim-vinculo-revela { fill: none; stroke: var(--white); stroke-width: 12; stroke-dasharray: 1 1; stroke-dashoffset: 1; }

/* ---------- Cita del informe ---------- */
.sim-tarjeta-fondo { fill: var(--brand-primary); stroke: var(--white); stroke-opacity: 0.28; stroke-width: 1; }
.sim-pastilla { fill: none; stroke: var(--white); stroke-opacity: 0.7; stroke-width: 1; }

/* ---------- Texto (mínimo 14 u en la ancha y 13,5 u en la estrecha) ---------- */
.sim-svg text { fill: var(--white); font-family: var(--font-text); }
.sim-svg .sim-t-titulo {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 14px;
  letter-spacing: 0.16em;
}
.sim-svg .sim-t-rotulo { font-family: var(--font-display); font-weight: 600; font-size: 14px; }
.sim-svg .sim-t-cian { fill: var(--brand-margin); }
.sim-svg .sim-t-cita { font-weight: 500; font-size: 15px; }
.sim-svg .sim-t-etiqueta {
  fill: var(--white);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.12em;
}
.sim-svg .sim-t-leyenda { font-weight: 500; font-size: 14px; fill-opacity: 0.86; }
.sim-svg .sim-duda {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 16px;
  fill-opacity: 0.55;
}
.sim-svg[data-disposicion="estrecho"] .sim-t-cita { font-size: 14px; }
.sim-svg[data-disposicion="estrecho"] .sim-t-etiqueta,
.sim-svg[data-disposicion="estrecho"] .sim-t-leyenda { font-size: 13.5px; }

/* ---------- Leyenda ---------- */
.sim-leyenda-linea { stroke: var(--white); stroke-opacity: 0.16; stroke-width: 1; }
.sim-ley-intento { fill: none; stroke: var(--white); stroke-width: 1.75; }
.sim-ley-vinculo { stroke: var(--brand-margin); stroke-width: 2; stroke-dasharray: 4 3; stroke-linecap: round; }
.sim-ley-radio {
  fill: none;
  stroke: var(--white);
  stroke-opacity: 0.8;
  stroke-width: 1.25;
  stroke-dasharray: 2 3;
  stroke-linecap: round;
}

/* ==========================================================================
   Transiciones. Cada regla lleva la transición del estado de llegada: al ir
   al acto 3 los intentos se retiran en su lugar y luego aparece el vínculo; al
   volver, el vínculo se retira primero y los intentos reaparecen donde estaban.
   ========================================================================== */
.sim-intento {
  transform: translate(var(--x), var(--y)) scale(1);
  transition:
    transform 0.56s var(--salida) calc(var(--i) * var(--paso) + 0.08s),
    opacity 0.25s ease calc(var(--i) * var(--paso) + 0.08s);
}
/* En el acto 3 los intentos se retiran en su lugar: no convergen al sitio (nada mide a Froz3D). */
.sim-svg[data-modo="froz3d"] .sim-intento {
  transform: translate(var(--x), var(--y)) scale(0.2);
  opacity: 0;
  transition:
    transform 0.3s var(--curva) calc(var(--i) * 12ms),
    opacity 0.2s ease calc(var(--i) * 12ms + 0.1s);
}
.sim-radio, .sim-sitio-real { transition: opacity 0.3s ease 0.3s; }
.sim-svg[data-modo="froz3d"] .sim-radio,
.sim-svg[data-modo="froz3d"] .sim-sitio-real { opacity: 0; transition: opacity 0.2s ease; }

.sim-solo-tradicional { transition: opacity 0.35s ease 0.3s; }
.sim-svg[data-modo="froz3d"] .sim-solo-tradicional { opacity: 0; transition: opacity 0.25s ease; }

/* Lo cian no se funde: aparece de una vez, con su retardo (opacidad a saltos; con visibility
   asomaría cuando el dibujo plano está oculto bajo el 3D). */
.sim-solo-froz3d { opacity: 0; }
.sim-svg[data-modo="froz3d"] .sim-solo-froz3d { opacity: 1; transition: opacity 0s linear 0.62s; }

.sim-vinculo-revela { transition: stroke-dashoffset 0.35s var(--curva); }
.sim-svg[data-modo="froz3d"] .sim-vinculo-revela {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.6s var(--curva) 0.18s;
}

/* Una copia translúcida de la pieza, corrida sobre la cavidad: apoyada, no calzada. La hondura
   de la cavidad sigue a la vista por debajo. */
.sim-cavidad-pieza {
  fill: var(--accent-innovation);
  fill-opacity: 0.4;
  stroke: var(--white);
  stroke-opacity: 0.9;
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.sim-svg[data-modo="froz3d"] .sim-cavidad-pieza { opacity: 1; transition: opacity 0.5s ease 0.3s; }

/* La marca cian del sitio entra por escala, sin fundido. */
.sim-sitio-marca {
  transform: scale(0);
  transition: transform 0.25s var(--curva);
}
.sim-svg[data-modo="froz3d"] .sim-sitio-marca {
  transform: scale(1);
  transition: transform 0.45s var(--salida) 0.58s;
}

/* Actos del relato en el dibujo plano (respaldo y póster). 0: solo la pieza y el lecho, mientras
   carga el 3D. 1: además la marca, su rótulo y la tarjeta. Lo demás llega en el acto 2. */
.sim-svg[data-acto="0"] .sim-marca,
.sim-svg[data-acto="0"] .sim-rot-margen,
.sim-svg[data-acto="0"] .sim-tarjeta,
.sim-svg[data-acto="0"] .sim-leyenda,
.sim-svg[data-acto="0"] .sim-del-acto-2,
.sim-svg[data-acto="0"] .sim-radio,
.sim-svg[data-acto="0"] .sim-sitio-real,
.sim-svg[data-acto="0"] .sim-rot-sitio,
.sim-svg[data-acto="1"] .sim-leyenda,
.sim-svg[data-acto="1"] .sim-del-acto-2,
.sim-svg[data-acto="1"] .sim-radio,
.sim-svg[data-acto="1"] .sim-sitio-real,
.sim-svg[data-acto="1"] .sim-rot-sitio { visibility: hidden; }

/* Entrada, una sola vez al aparecer el escenario: los intentos se posan de a
   uno, más lento que al alternar, y las dudas al final. */
.sim-svg[data-intro="pendiente"] .sim-intento {
  transform: translate(var(--x), var(--y)) scale(0.2);
  opacity: 0;
}
.sim-svg[data-intro="pendiente"] .sim-duda,
.sim-svg[data-intro="pendiente"] .sim-hilo { opacity: 0; }
.sim-svg[data-intro="curso"] { --paso: 80ms; }
.sim-duda,
.sim-hilo { transition: opacity 0.4s ease 1.1s; }

@media (prefers-reduced-motion: reduce) {
  .sim-svg,
  .sim-svg * { transition: none !important; }
}

/* ==========================================================================
   Módulo: Simulador 3D (simulador3d.js, con el host simulador.js)
   ========================================================================== */
/* El relato en 3 actos de la sección 05. La escena pone su capa (.sim3d-capa: el lienzo WebGL
   transparente y, encima, las notas en SVG y HTML) dentro del escenario azul noche. Sobre él solo
   van blanco, cian y azul profundo; el cian es solo la marca y su vínculo. Ninguna transición en
   la capa: cada valor lo fija simulador3d.js en cada cuadro (la regla global de movimiento
   reducido las dejaría a medias). El dibujo plano (.sim-svg) sigue debajo, oculto con visibility
   mientras hay 3D: es el póster y el respaldo. */
.sim__escenario { position: relative; }
.sim3d-capa { position: absolute; inset: 0; pointer-events: none; }
.sim3d-capa, .sim3d-capa * { transition: none !important; animation: none !important; }
.sim3d-capa canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.sim3d-notas { position: absolute; inset: 0; width: 100%; height: 100%; overflow: hidden; }
.sim3d-contorno { fill: none; stroke: var(--white); stroke-opacity: 0.9; stroke-width: 1.5; stroke-linejoin: round; }
.sim3d-intento { fill: none; stroke: var(--white); stroke-width: 1.75; vector-effect: non-scaling-stroke; }
/* El sitio real lleva funda azul profundo: entre los intentos de dentro se sigue distinguiendo. */
.sim3d-sitio-funda { fill: none; stroke: var(--brand-primary); stroke-width: 4.5; vector-effect: non-scaling-stroke; }
.sim3d-sitio { fill: none; stroke: var(--white); stroke-width: 1.75; stroke-dasharray: 3.3 2.2; vector-effect: non-scaling-stroke; }
.sim3d-sitio-centro { fill: var(--white); stroke: var(--brand-primary); stroke-width: 1; }
.sim3d-radio { fill: none; stroke: var(--white); stroke-opacity: 0.85; stroke-width: 1.25; stroke-dasharray: 2 4; stroke-linecap: round; }
.sim3d-hilo { stroke: var(--white); stroke-opacity: 0.8; stroke-width: 1.5; stroke-dasharray: 0.1 5; stroke-linecap: round; }
.sim3d-guia { stroke: var(--white); stroke-opacity: 0.55; stroke-width: 1; }
/* El vínculo y la retícula llevan funda azul profundo: el cian solo no llega a 3:1 sobre los
   sólidos azul y violeta. */
.sim3d-vinculo-funda, .sim3d-reticula-funda { fill: none; stroke: var(--brand-primary); stroke-width: 5; stroke-linecap: round; }
.sim3d-vinculo { fill: none; stroke: var(--brand-margin); stroke-width: 2; stroke-dasharray: 6 5; stroke-linecap: round; }
.sim3d-reticula { fill: none; stroke: var(--brand-margin); stroke-width: 2; stroke-linecap: round; }
.sim3d-rotulo, .sim3d-duda, .sim3d-tarjeta { position: absolute; left: 0; top: 0; color: var(--white); }
/* Los rótulos llevan un fondo del color del escenario: una línea de la capa (un hilo, una guía)
   pasa por detrás y no los cruza. */
.sim3d-rotulo {
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--navy-deep);
  white-space: nowrap;
  font: 600 0.8125rem/1.25 var(--font-display);
}
.sim3d-rotulo--titulo { font-weight: 800; letter-spacing: 0.16em; }
.sim3d-rotulo--cian { color: var(--brand-margin); }
.sim3d-duda { font: 700 1rem/1 var(--font-display); }
.sim3d-tarjeta {
  box-sizing: border-box;
  padding: 10px 14px 12px;
  background: var(--brand-primary);
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 10px;
}
.sim3d-pastilla {
  display: inline-block;
  padding: 3px 10px;
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 11px;
  font: 700 0.75rem/1.2 var(--font-display);
  letter-spacing: 0.12em;
}
.sim3d-cita { margin-top: 8px; font: 500 0.9375rem/1.3 var(--font-text); }
.sim3d-cita-resto { visibility: hidden; }
.sim3d-capa--estrecha .sim3d-tarjeta { padding: 8px 12px 10px; }
.sim3d-capa--estrecha .sim3d-cita { margin-top: 6px; font-size: 0.875rem; }
.sim3d-capa--compacta .sim3d-rotulo { font-size: 0.75rem; }

/* Estados del host (data-sim-3d en [data-sim]): «cargando» (el dibujo plano como póster, o el
   último cuadro congelado), «animado» (el 3D) y «sin3d» (el dibujo plano como respaldo). */
.sim[data-sim-3d="animado"] .sim-svg,
.sim--congelado .sim-svg { visibility: hidden; }
.sim[data-sim-3d="sin3d"] .sim3d-capa { display: none; }
/* Con 3D el escenario se arrastra para girar la vista; el gesto vertical sigue desplazando la
   página. */
.sim[data-sim-3d="animado"] .sim__escenario { touch-action: pan-y pinch-zoom; cursor: grab; user-select: none; -webkit-user-select: none; }
.sim[data-sim-3d="animado"] .sim__escenario.sim--arrastrando { cursor: grabbing; }

/* Banda con el acto en curso, arriba a la izquierda del escenario (la pone el host). Solo sobre
   el 3D o su cuadro congelado: el dibujo plano trae su tarjeta en ese lugar. */
.sim__banda {
  position: absolute;
  left: 14px; top: 9px;
  margin: 0;
  font: 600 0.8125rem/1.3 var(--font-display);
  color: var(--white);
  pointer-events: none;
}
.sim:not([data-sim-3d="animado"]):not(.sim--congelado) .sim__banda { visibility: hidden; }

/* Filas bajo el escenario: controles, pasos y leyenda. Llegan con «hidden» en el HTML (una hoja
   anterior en caché no las mostraría sin estilo) y el host las muestra; con JavaScript su alto se
   reserva desde el primer pintado, para que nada salte cuando aparecen. Si el host no llegó
   (.sim--sin-modulo) o es uno anterior que no las muestra (.sim--sin-relato; las dos clases las
   pone el <head>), dejan de reservarse. */
.sim__controles { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 18px; min-height: 44px; }
.js .sim:not(.sim--sin-modulo):not(.sim--sin-relato) > .sim__controles[hidden] { display: flex !important; visibility: hidden; }
.js .sim:not(.sim--sin-modulo):not(.sim--sin-relato) > .sim__relato[hidden] { display: grid !important; visibility: hidden; }
.js .sim:not(.sim--sin-modulo):not(.sim--sin-relato) > .sim__leyenda[hidden] { display: grid !important; visibility: hidden; }
.sim__controles .btn-texto { min-height: 44px; color: var(--white); }
/* «Pausar animación» se retira al final sin soltar su lugar: «Ver de nuevo» no se mueve. */
.sim__controles > [hidden] { display: block !important; visibility: hidden; }
/* El conmutador de pausa: dos barras mientras corre y un triángulo en pausa (su nombre no cambia;
   el estado lo dice aria-pressed). */
.sim__controles [aria-pressed]::before {
  content: "";
  display: inline-block;
  box-sizing: border-box;
  width: 0.6em;
  height: 0.7em;
  margin-right: 0.5em;
  border: solid currentColor;
  border-width: 0 0.2em;
}
.sim__controles [aria-pressed="true"]::before {
  border-color: transparent transparent transparent currentColor;
  border-width: 0.35em 0 0.35em 0.6em;
}
/* Giro de la vista: dos botones en la esquina del escenario, como en un mapa. Solo con el 3D a la
   vista. */
.sim__giro { position: absolute; right: 8px; bottom: 8px; z-index: 2; display: inline-flex; gap: 8px; }
.sim:not([data-sim-3d="animado"]) .sim__giro { visibility: hidden; }
.sim__pista { margin-left: auto; font: 500 0.8125rem/1.3 var(--font-text); color: var(--on-dark-muted); }
.sim__girar {
  display: inline-grid;
  place-items: center;
  width: 44px; height: 44px;
  padding: 0;
  background: var(--navy-deep);
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 50%;
  color: var(--white);
  cursor: pointer;
}
.sim__girar:hover { background: var(--brand-primary); }
.sim__girar[aria-disabled="true"] { color: rgba(255, 255, 255, 0.4); border-color: rgba(255, 255, 255, 0.2); cursor: default; }
.sim__girar[aria-disabled="true"]:hover { background: var(--navy-deep); }
.sim__girar svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* En el respaldo no hay nada que pausar ni girar: los controles ceden su lugar sin mover la fila. */
.sim[data-sim-3d="sin3d"] .sim__controles > * { visibility: hidden; }

/* Pasos: tres botones (número y título) y, debajo, la frase del acto en curso. Título y frase de
   cada paso están siempre en su botón para los lectores de pantalla. */
.sim__relato { display: grid; gap: 10px; }
.sim__actos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0; padding: 0; list-style: none; }
.sim__actos > li { display: flex; }                  /* el botón toma el alto de la fila */
.sim__ir {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  padding: 6px 10px;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 12px;
  font: 600 0.9375rem/1.25 var(--font-display);
  color: var(--white);
  text-align: left;
  cursor: pointer;
}
.sim__ir:hover { background: rgba(255, 255, 255, 0.08); }
.sim__num {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border: 2px solid var(--white);
  border-radius: 50%;
  font: 800 0.875rem/1 var(--font-display);
}
.sim__ir[aria-current="step"] { background: var(--white); border-color: var(--white); color: var(--brand-primary); }
.sim__ir[aria-current="step"] .sim__num { background: var(--brand-primary); border-color: var(--brand-primary); color: var(--white); }
.sim__txt strong { font-weight: 600; }
/* La frase va oculta a la vista dentro del botón (se lee en .sim__activa) y sigue en su nombre. */
.sim__frase {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
/* Alto reservado para la frase más larga (la del acto 2, tres renglones): al cambiar de acto nada
   salta. Mientras la escena va camino a un acto pedido queda en blanco. */
.sim__activa { margin: 0; min-height: 4.65em; min-height: 3lh; color: var(--on-dark-muted); }
.sim__activa strong { color: var(--white); font-weight: 600; }
.sim__activa .sim__frase { position: static !important; width: auto; height: auto; margin: 0; clip: auto; white-space: normal; }

/* Leyenda: una lista por acto, apiladas en la misma celda (la fila reserva la más alta) y a la
   vista solo la del acto que el escenario muestra. La marca, un disco cian con aro azul profundo. */
.sim__leyenda { display: grid; min-height: 24px; font: 500 0.8125rem/1.3 var(--font-text); color: var(--on-dark-muted); }
.sim__leyenda ul {
  grid-area: 1 / 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: start;
  gap: 6px 20px;
  margin: 0;
  padding: 0;
  list-style: none;
  visibility: hidden;
}
.sim__leyenda li { display: inline-flex; align-items: center; gap: 8px; }
.sim[data-sim-rotulo="1"] .sim__leyenda [data-sim-ley="1"],
.sim[data-sim-rotulo="2"] .sim__leyenda [data-sim-ley="2"],
.sim[data-sim-rotulo="3"] .sim__leyenda [data-sim-ley="3"] { visibility: visible; }
/* El dibujo plano trae su propia clave dentro del escenario. */
.sim[data-sim-3d="sin3d"] .sim__leyenda [data-sim-ley] { visibility: hidden; }
.sim__muestra { flex: none; box-sizing: border-box; width: 14px; height: 14px; }
.sim__muestra--intento { width: 13px; height: 10px; border: 1.75px solid var(--white); border-radius: 50%; }
.sim__muestra--radio { border: 1.5px dashed var(--white); border-radius: 50%; }
.sim__muestra--marca { width: 11px; height: 11px; margin: 0 3px; border-radius: 50%; background: var(--brand-margin); box-shadow: 0 0 0 2.5px var(--brand-primary), 0 0 0 3.5px var(--white); }
.sim__muestra--vinculo { width: 18px; height: 0; border-top: 2px dashed var(--brand-margin); }
.sim__muestra--copia { border: 1.5px solid var(--white); border-radius: 4px; background: rgba(112, 93, 198, 0.4); }

/* Disposición. En escritorio las filas van bajo el escenario, en sus 7 columnas, y el panel al
   lado a todo el alto. En una columna el panel sigue a las filas, con aire. */
.sim__controles, .sim__relato, .sim__leyenda { grid-column: 1 / span 7; }
@media (min-width: 1100px) {
  /* La fila del escenario se mide por su contenido: con overflow: hidden su mínimo automático es
     0 y el panel repartiría su alto entre filas vacías. */
  .sim { grid-template-rows: min-content; }
  .sim__escenario { grid-row: 1; }
  .sim__controles { grid-row: 2; }
  .sim__relato { grid-row: 3; }
  .sim__leyenda { grid-row: 4; }
  .sim__panel { grid-row: 1 / span 4; }
  /* Con el HTML anterior (sin las filas nuevas) o sin ellas a la vista no hay filas que abarcar. */
  .sim:not(:has(> .sim__relato)) > .sim__panel,
  .sim--sin-relato .sim__panel { grid-row: 1; }
  .no-js .sim__panel, .sim--sin-modulo .sim__panel { grid-row: auto; }
  /* Las dos explicaciones ocupan la misma celda: el panel no cambia de alto cuando el relato pasa
     solo al acto 3 y el botón de abajo no salta. */
  .sim[data-sim-modo-actual] .sim__explica { display: grid; }
  .sim[data-sim-modo-actual] .sim__explica > div { grid-area: 1 / 1; margin-top: 0; }
  .sim[data-sim-modo-actual] .sim__explica > div[hidden] { display: block !important; visibility: hidden; }
}
@media (max-width: 1099px) {
  .sim__controles, .sim__relato, .sim__leyenda { grid-column: 1 / -1; }
  .sim__panel { margin-top: 16px; }
}
/* Sin el host (no llegó o falló): como sin JavaScript. Se leen las dos explicaciones. */
.sim--sin-modulo .sim__escenario, .sim--sin-modulo .sim__modo { display: none; }
.sim--sin-modulo .sim__panel { grid-column: 1 / -1; }
/* En teléfono los pasos son tres fichas con su número (el título queda en el nombre del botón y
   en la frase de abajo). Orden a la vista, el mismo del foco: escenario, controles, pasos, los dos
   radios, la frase del acto, la leyenda y la explicación: al comparar, el escenario sigue cerca. */
@media (max-width: 699px) {
  .js .sim:not(.sim--sin-modulo):not(.sim--sin-relato) .sim__panel,
  .js .sim:not(.sim--sin-modulo):not(.sim--sin-relato) > .sim__relato { display: contents; }
  .js .sim:not(.sim--sin-modulo):not(.sim--sin-relato) > .sim__relato[hidden] { display: contents !important; }
  .sim__panel { margin-top: 0; }
  .sim__escenario { order: 1; }
  .sim__controles { order: 2; }
  .sim__actos { order: 3; grid-template-columns: repeat(3, 48px); }
  .sim__modo { order: 4; }
  .sim__activa { order: 5; min-height: 7.75em; min-height: 5lh; }
  .sim__leyenda { order: 6; }
  .sim__explica { order: 7; margin-top: 12px; }
  .sim__panel .btn { order: 8; }
  .sim__ir { justify-content: center; padding: 6px; }
  .sim__ir .sim__txt {
    position: absolute !important;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0);
    white-space: nowrap; border: 0;
  }
  .sim__pista { display: none; }
}
/* La barra fija de abajo (móvil) se retira mientras el escenario está a la vista: taparía los
   controles. Ya pasa con la demo de la sección 02 y con el panel de Pacientes. */
.sim-a-la-vista .barra-movil { display: none !important; }

/* Alto contraste: el escenario y la leyenda conservan sus colores (son el dibujo y su clave); el
   paso y el radio activos se distinguen por el borde cuando el sistema sustituye los rellenos, y
   el triángulo de la pausa conserva su forma (con colores forzados los bordes transparentes se
   pintan). */
@media (forced-colors: active) {
  .sim__escenario { forced-color-adjust: none; }
  .sim__leyenda { forced-color-adjust: none; padding: 6px 10px; border-radius: 8px; background: var(--brand-primary); }
  .sim__controles [aria-pressed="true"]::before { forced-color-adjust: none; border-color: transparent transparent transparent ButtonText; }
  .sim__ir[aria-current="step"] { border: 4px double ButtonText; }
  .sim__modo input:checked + span { border: 4px double ButtonText; }
}
/* Al imprimir: el dibujo plano del acto en curso (trae su clave), los títulos de los pasos con la
   frase del acto en curso y las dos explicaciones como texto. */
@media print {
  #simulador { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .sim3d-capa, .sim__banda, .sim__controles, .sim__modo, .sim__leyenda, .sim__giro, .sim__activa { display: none !important; }
  .sim .sim-svg { visibility: visible !important; }
  .sim__frase, .sim__ir .sim__txt { position: static !important; width: auto; height: auto; margin: 0; clip: auto; white-space: normal; }
  .sim__ir:not([aria-current="step"]) .sim__frase { display: none !important; }
  .sim__actos { grid-template-columns: 1fr; }
  .sim .sim__explica, .sim[data-sim-modo-actual] .sim__explica { display: block; }
  .sim .sim__explica > div[hidden], .sim[data-sim-modo-actual] .sim__explica > div[hidden] { display: block !important; visibility: visible; }
  .sim .sim__explica > div + div, .sim[data-sim-modo-actual] .sim__explica > div + div { margin-top: 24px; }
}

/* ==========================================================================
   Módulo: Formulario y comportamiento de página (formulario.js, pagina.js)
   ========================================================================== */
/* ==========================================================================
   formulario.css — lo que formulario.js y pagina.js necesitan más allá de
   estilos.css. Se fusiona en estilos.css cuando la página se promueva.
   Todo el movimiento es de entrada y corto; con movimiento reducido no hay.
   ========================================================================== */

/* ---------- Envío en curso ---------- */
/* Mientras envía, el botón lleva aria-disabled (no disabled, para no perder el
   foco) y no se ve «apagado»: anula la opacidad 0.55 de .btn[aria-disabled]
   de estilos.css para que el anillo y «Enviando…» se lean bien. */
.btn[data-form-enviar][aria-disabled="true"] {
  opacity: 1;
  cursor: progress;
}
[data-form-enviar][aria-disabled="true"]::before {
  content: "";
  flex: none;
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: f3d-giro 0.8s linear infinite;
}
@keyframes f3d-giro { to { transform: rotate(360deg); } }

/* ---------- Panel de resultado ---------- */
/* Error o envío incierto: el panel queda bajo el formulario, con aire. */
.form:not([hidden]) + .form__estado { margin-top: 24px; }
.form__estado .btn-texto {
  min-height: 44px;
  align-self: center;
}
/* «Reintentar» mientras reenvía (aria-disabled, conserva el foco). */
.form__estado .btn-texto[aria-disabled="true"] {
  cursor: progress;
  text-decoration: none;
  color: var(--text-secondary);
}
@media (max-width: 699px) {
  .form__estado { padding: 20px; }
  .form__estado-acciones .btn { flex: 1 1 100%; }
}

/* ---------- Menú móvil: las barras pasan a una cruz ---------- */
.nav-toggle__barras::before,
.nav-toggle__barras::after { transition: transform 0.2s ease, top 0.2s ease; }
.nav-toggle[aria-expanded="true"] .nav-toggle__barras { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__barras::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__barras::after { top: 0; transform: rotate(-45deg); }

/* ---------- Entradas ---------- */
@media (prefers-reduced-motion: no-preference) {
  .form__estado:not([hidden]),
  .form__interes:not([hidden]),
  .aviso-paciente:not([hidden]),
  .campo__error:not([hidden]) {
    animation: f3d-aparece 0.28s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .barra-movil:not([hidden]) {
    animation: f3d-sube 0.26s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
}
@media (max-width: 999px) and (prefers-reduced-motion: no-preference) {
  .js .nav.is-open { animation: f3d-aparece 0.2s ease-out both; }
}
@keyframes f3d-aparece { from { opacity: 0; transform: translateY(-4px); } }
@keyframes f3d-sube { from { transform: translateY(100%); } }

/* ---------- Movimiento reducido ---------- */
/* El texto «Enviando…» basta; un anillo detenido no informa nada. */
@media (prefers-reduced-motion: reduce) {
  [data-form-enviar][aria-disabled="true"]::before { display: none; }
}

/* ==========================================================================
   Intro de marca · va al final: su cascada es la de la hoja que era aparte
   ========================================================================== */

/* Intro de marca a pantalla completa (intro-marca.js, intro-escena.js).

   Base anti-destello: el script del <head> decide html.intro-pendiente antes del primer
   pintado, y esta hoja (bloqueante) pinta la capa azul profundo desde el primer cuadro,
   así la página nunca asoma antes de la intro. Si ningún módulo la activa en 7 s
   (html.intro-activa o intro-cargando), la capa se retira sola. Con el módulo en carga,
   su plazo de 15 s controla la salida y «Saltar» sigue disponible.

   Pares de color de la guía v3: blanco sobre azul profundo; cian sobre azul profundo solo en
   rótulos; azul profundo sobre blanco frío. El cian nunca va como texto sobre fondo claro.
   intro-marca.js escribe opacidades y transformaciones en línea en cada cuadro; aquí van la
   composición y los estados de partida. */

.intro { display: none; }
html.intro-pendiente .intro {
  display: block;
  position: fixed;
  inset: 0;
  height: 100dvh;
  z-index: 100;
  overflow: hidden;
  background: var(--brand-primary);
  color: var(--white);
  --focus: var(--brand-margin);
}
html.intro-pendiente:not(.intro-activa):not(.intro-cargando) .intro { animation: intro-retirar 0s 7s forwards; }
@keyframes intro-retirar { to { visibility: hidden; opacity: 0; } }
html.intro-saltada .intro { display: none !important; }
/* Ya activa, el fondo lo pinta la capa [data-intro-fondo] (puede aclararse y desvanecerse). */
html.intro-activa .intro { background: transparent; }

/* Hasta que el módulo toma el control solo se ven el fondo y «Saltar». */
html.intro-pendiente:not(.intro-activa) .intro > :not(.intro__saltar):not(.intro__fondo) { visibility: hidden; }

/* «Saltar» existe y funciona desde el primer cuadro, antes de que cargue ningún módulo. Tiene
   fondo propio: su contraste no depende del cambio de fondo de la escena D. */
.intro__saltar {
  position: absolute;
  top: max(16px, env(safe-area-inset-top));
  right: max(16px, env(safe-area-inset-right));
  z-index: 5;
  min-height: 44px;
  padding: 10px 16px;
  background: rgba(16, 43, 70, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: var(--radius-control);
  color: var(--white);
  font: 600 0.9375rem/1 var(--font-display);
  cursor: pointer;
}
.intro__saltar:hover { border-color: var(--white); }

/* ---------- Composición ---------- */
.intro {
  --placa-fondo: #F6FAFD;              /* fondo del logo maestro: las franjas calzan sin costura */
  --nombre-fs: clamp(40px, min(5.4vw, 9.5vh), 84px);
  --placa-top: clamp(72px, 12vh, 124px);
  --placa-alto: calc(var(--nombre-fs) * 1.38);
  --margen-lateral: 24px;
  --logo-w: 640px;                     /* 640: los cortes de las franjas caen en px enteros */
  --logo-h: calc(var(--logo-w) * 174 / 640);
  --logo-x: calc(50% - var(--logo-w) / 2);
  --logo-y: calc(50% - var(--logo-h));  /* intro-marca.js la fija en px enteros */
  --sombra: 1;
}
html.intro-pendiente .intro[data-tono="claro"] { --focus: var(--action-primary); }
.intro[data-tono="claro"] .intro__saltar {
  background: var(--white);
  border-color: rgba(16, 43, 70, 0.4);
  color: var(--brand-primary);
}
.intro[data-tono="claro"] .intro__saltar:hover { border-color: var(--brand-primary); }

/* Sin color propio: hasta que el módulo toma el control pinta la capa (.intro); después,
   intro-marca.js le da el color de cada cuadro. */
.intro__fondo {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.intro__escena {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}
.intro__lienzo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Placa clara con el nombre: sobre fondo oscuro, el logo solo aparece en placa blanco frío
   (guía p.12). El ::before es el fondo de la placa: se angosta sin recortar a sus hijas. */
.intro__placa {
  position: absolute;
  z-index: 1;
  top: var(--placa-top);
  left: 0;
  right: 0;
  width: max-content;
  margin-inline: auto;
  padding: 0.17em 0.4em 0.21em;
  font-size: var(--nombre-fs);
  opacity: 0;
}
.intro__placa::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: var(--placa-recorte, 0px);
  background: var(--placa-fondo);
  border-radius: 0.2em;
  box-shadow:
    0 0 0 1px rgba(61, 200, 217, calc(0.3 * var(--sombra))),
    0 30px 70px -28px rgba(3, 12, 22, calc(0.6 * var(--sombra)));
}
.intro__nombre {
  position: relative;
  margin: 0;
  font: 800 1em/1 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--brand-primary);
  white-space: nowrap;
}
.intro__nombre > span { display: inline-block; }
.intro__placa-capa {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  opacity: 0;
}
.intro__placa-capa img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
}
/* Línea del escáner que pasa sobre «Froz»: decorativa, no es texto. */
.intro__barrido {
  position: absolute;
  top: 0.1em;
  bottom: 0.1em;
  left: 0;
  width: 2px;
  border-radius: 1px;
  background: var(--brand-margin);
  box-shadow: 0 0 10px 1px rgba(61, 200, 217, 0.55);
  opacity: 0;
}

.intro__bajada,
.intro__sigla {
  position: absolute;
  z-index: 3;
  left: var(--margen-lateral);
  right: var(--margen-lateral);
  top: calc(var(--placa-top) + var(--placa-alto) + 22px);
  margin: 0;
  text-align: center;
  opacity: 0;
}
.intro__bajada {
  font: 500 clamp(1rem, 0.9rem + 0.45vw, 1.3125rem)/1.45 var(--font-text);
  color: var(--white);
}
/* Sigla: rótulo cian sobre azul profundo; en el cierre, azul profundo sobre blanco frío. */
.intro__sigla {
  font: 700 0.875rem/1.3 var(--font-display);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-margin);
}
.intro[data-tono="claro"] .intro__sigla {
  top: calc(var(--logo-y) - 42px);
  color: var(--brand-primary);
}

/* Los 4 pasos (solo títulos, un paso a la vez). intro-marca.js mide la placa, la sigla y el
   texto y fija --pasos-x/-y/-w: el texto nunca queda sobre la placa, la sigla ni «Saltar».
   data-pasos: «dividida» (escritorio y apaisada baja: escena a la izquierda, texto a la
   derecha), «apilada» (escena arriba, texto abajo, centrado) o «baja» (zoom al 400 %: el texto
   bajo la sigla, más chico). El tamaño lo manda rem, sin vw ni vh: crece con el zoom (WCAG
   1.4.4). Un vw hacía el título más grande en px CSS al 100 % que al 200 % en escritorios anchos
   (45 px a 1920×1080 contra 40 px a 960×540, el 177 %). En dividida mide 2,25 rem (36 px), menos
   o igual que en las composiciones a las que se llega con zoom al 200 % en escritorio (2,5 rem
   bajo 600 px de alto, 2,25 rem bajo 380 y bajo 340 con puntero fino; si no cabe, intro-marca.js
   angosta la escena antes de bajar de 2,25 rem; en apilada con puntero fino, 2,25 rem si la
   escena conserva 120 px); en apilada, 1,5 rem. El margen inferior respeta el área segura
   (intro-marca.js lo lee). */
.intro__pasos {
  position: absolute;
  z-index: 3;
  left: var(--pasos-x, 24px);
  top: var(--pasos-y, 60%);
  width: var(--pasos-w, calc(100% - 48px));
  margin: 0 0 max(16px, env(safe-area-inset-bottom, 0px));
  color: var(--white);
  pointer-events: none;
  opacity: 0;
}
.intro__lista {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Los cuatro títulos ocupan la misma celda: el bloque mide lo que el más alto. Cada uno se
   apoya abajo, así el título queda siempre a la misma distancia del indicador de avance. */
.intro__paso {
  grid-area: 1 / 1;
  align-self: end;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.875rem;
  opacity: 0;
}
/* Número relleno, como el paso activo de la tarjeta: blanco con el número en azul profundo. */
.intro__num {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--white);
  color: var(--brand-primary);
  font: 800 1.125rem/1 var(--font-display);
}
.intro__titulo {
  max-width: 13em;
  font: 700 2.25rem/1.12 var(--font-display);
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.intro__avance {
  display: flex;
  gap: 6px;
  margin-top: 1.5rem;
}
.intro__avance span {
  position: relative;
  width: 2.75rem;
  height: 4px;
  overflow: hidden;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.26);
}
.intro__avance i {
  position: absolute;
  inset: 0;
  background: var(--white);
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.intro[data-pasos="apilada"] .intro__pasos { text-align: center; }
.intro[data-pasos="apilada"] .intro__paso { align-items: center; gap: 0.625rem; }
.intro[data-pasos="apilada"] .intro__num { width: 2.125rem; height: 2.125rem; font-size: 1rem; }
.intro[data-pasos="apilada"] .intro__titulo {
  max-width: 15em;
  margin-inline: auto;
  font-size: 1.5rem;
  line-height: 1.15;
}
.intro[data-pasos="apilada"] .intro__avance { justify-content: center; margin-top: 1.125rem; }
.intro[data-pasos="baja"] .intro__paso { flex-direction: row; align-items: center; gap: 0.625rem; }
.intro[data-pasos="baja"] .intro__num { width: 1.75rem; height: 1.75rem; font-size: 0.875rem; }
.intro[data-pasos="baja"] .intro__titulo { max-width: none; font-size: 1.125rem; line-height: 1.2; }
.intro[data-pasos="baja"] .intro__avance { margin-top: 0.5rem; }
.intro[data-pasos="baja"] .intro__avance span { width: 2rem; height: 3px; }
/* Dividida en pantallas bajas (teléfono girado, zoom al 200 %): número al lado del título. Con
   el zoom al 200 % el título mide 2 veces o más lo que mide al 100 % (2,5 rem a 720×450 contra
   2,25 rem a 1440×900); en las más bajas, 2,25 rem (el doble justo). Si no cabe, intro-marca.js
   angosta la escena antes de bajar de 2,25 rem (data-pasos-talla). */
@media (max-height: 599px) {
  .intro[data-pasos="dividida"] .intro__paso { flex-direction: row; gap: 0.75rem; }
  .intro[data-pasos="dividida"] .intro__num { width: 2rem; height: 2rem; margin-top: 0.25rem; font-size: 0.9375rem; }
  .intro[data-pasos="dividida"] .intro__titulo { font-size: 2.5rem; }
  .intro[data-pasos="dividida"] .intro__avance { margin-top: 1rem; }
}
@media (max-height: 380px) {
  .intro[data-pasos="dividida"] .intro__num { margin-top: 0.125rem; }
  .intro[data-pasos="dividida"] .intro__titulo { font-size: 2.25rem; }
}
/* Teléfonos girados (táctiles): el título, de 36–40 px en 2 o 3 líneas, pesaba más que la escena
   que explica. Baja a 1,75 rem (a lo más 2 líneas). Con zoom en escritorio (puntero fino) sigue
   creciendo como arriba (WCAG 1.4.4). */
@media (max-height: 420px) and (pointer: coarse) {
  .intro[data-pasos="dividida"] .intro__num { margin-top: 0; }
  .intro[data-pasos="dividida"] .intro__titulo { font-size: 1.75rem; line-height: 1.15; }
}
/* Muy bajas (menos de 340 px de alto): número y avance compactos. A esta altura se llega también
   con el zoom al 200 % en un portátil (1366×643 → 683×321; 1280×600 → 640×300), así que con
   puntero fino el título sigue en 2,25 rem (WCAG 1.4.4); solo en teléfonos chicos girados
   (táctiles) baja a 1,25 rem. */
@media (max-height: 340px) {
  /* El número (1,75 rem) es más alto que una línea de título chica: centrados, el título de una
     línea queda a la misma distancia del avance que el de dos. */
  .intro[data-pasos="dividida"] .intro__paso { align-items: center; }
  .intro[data-pasos="dividida"] .intro__num { width: 1.75rem; height: 1.75rem; margin-top: 0; font-size: 0.875rem; }
  .intro[data-pasos="dividida"] .intro__avance { margin-top: 0.5rem; }
  .intro[data-pasos="dividida"] .intro__avance span { width: 2rem; height: 3px; }
}
@media (max-height: 340px) and (pointer: coarse) {
  .intro[data-pasos="dividida"] .intro__titulo { font-size: 1.25rem; line-height: 1.2; }
  .intro[data-pasos="dividida"] .intro__avance { margin-top: 0.625rem; }
}
/* Si aun así el texto no cabe bajo la sigla (intro-marca.js lo mide), un escalón menos: primero
   2,25 rem (el mínimo con que el título crece al doble con el zoom al 200 %), luego 1,75 y 1,25.
   En la composición apilada con puntero fino, '0' es un escalón hacia arriba (2,25 rem). */
.intro[data-pasos-talla="0"] .intro__titulo { font-size: 2.25rem; line-height: 1.12; }
.intro[data-pasos-talla="1"] .intro__titulo { font-size: 1.75rem; line-height: 1.15; }
.intro[data-pasos-talla="2"] .intro__titulo { font-size: 1.25rem; line-height: 1.2; }

/* Logo final: solo píxeles del maestro. Tres franjas que se ensamblan y luego el logo
   completo, sin transformaciones en reposo (así se compara píxel por píxel). En el vuelo de F
   va una copia con fondo transparente (.intro__logo-vuelo): el maestro opaco dejaría una caja
   clara sobre el hero. */
.intro__logo {
  position: absolute;
  z-index: 3;
  left: var(--logo-x);
  top: var(--logo-y);
  width: var(--logo-w);
  height: var(--logo-h);
  transform-origin: 0 0;
}
.intro__capa,
.intro__logo-completo,
.intro__logo-vuelo {
  position: absolute;
  top: 0;
  height: 100%;
  max-width: none;
  opacity: 0;
}
.intro__capa[data-intro-capa="isotipo"] { left: 0; width: 29.375%; }
.intro__capa[data-intro-capa="froz"] { left: 29.375%; width: 41.71875%; }
.intro__capa[data-intro-capa="3d"] { left: 71.09375%; width: 28.90625%; }
.intro__logo-completo,
.intro__logo-vuelo { left: 0; width: 100%; }
/* Línea del escáner que cambia el 3D por el isotipo maestro (15,8–16,0 s): decorativa, no es
   texto, así que el cian va también sobre el fondo claro. */
.intro__escaneo {
  position: absolute;
  top: 0;
  left: 0;
  width: 29.375%;
  height: 2px;
  background: var(--brand-margin);
  box-shadow: 0 0 6px rgba(61, 200, 217, 0.45);
  opacity: 0;
  pointer-events: none;
}

.intro__cierre {
  position: absolute;
  z-index: 3;
  left: var(--margen-lateral);
  right: var(--margen-lateral);
  top: calc(var(--logo-y) + var(--logo-h) + 26px);
  text-align: center;
  color: var(--brand-primary);
}
.intro__lema {
  margin: 0;
  font: 700 clamp(1.25rem, 0.95rem + 0.95vw, 1.875rem)/1.25 var(--font-display);
  letter-spacing: -0.01em;
  opacity: 0;
}
.intro__respaldos {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 24px 64px;
  margin: 38px 0 0;
  padding: 0;
  list-style: none;
}
.intro__respaldos li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  font: 600 0.9375rem/1.3 var(--font-display);
  opacity: 0;
}
.intro__respaldos img { width: auto; max-width: none; }
.intro__respaldos li:first-child img { height: 44px; }
.intro__respaldos li:last-child img { height: 34px; }
.intro__firma {
  margin: 30px 0 0;
  font: 500 0.9375rem/1.4 var(--font-text);
  color: var(--text-secondary);
  opacity: 0;
}

/* Durante la intro: el logo del encabezado espera al que vuela hacia él, y el póster de la
   tarjeta se oculta si el isotipo 3D va a aterrizar en su lienzo. El título del hero nunca
   se oculta (es el candidato a LCP): solo se desplaza con transform. */
html.intro-activa .marca img { opacity: 0; }
html.intro-aterriza .visor__poster { visibility: hidden; }

/* ---------- Tableta y pantallas bajas ---------- */
@media (max-width: 1099px), (max-height: 760px) {
  .intro { --logo-w: 480px; }
}

/* ---------- Móvil vertical ---------- */
@media (max-width: 699px) {
  .intro {
    --nombre-fs: clamp(28px, 9vw, 40px);
    --placa-top: max(78px, calc(env(safe-area-inset-top) + 66px));
    --margen-lateral: 16px;
    --logo-w: min(320px, 100vw - 32px); /* aire alrededor del logo también a 320 px */
  }
  .intro__bajada { font-size: 1rem; }
  .intro__sigla { font-size: 0.8125rem; letter-spacing: 0.14em; }
  .intro[data-tono="claro"] .intro__sigla { top: calc(var(--logo-y) - 34px); }
  .intro__cierre { top: calc(var(--logo-y) + var(--logo-h) + 20px); }
  .intro__lema { font-size: 1.25rem; }
  .intro__respaldos { flex-direction: column; align-items: center; gap: 18px; margin-top: 26px; }
  .intro__respaldos li { gap: 8px; font-size: 0.875rem; }
  .intro__respaldos li:first-child img { height: 40px; }
  .intro__respaldos li:last-child img { height: 30px; }
  .intro__firma { margin-top: 24px; font-size: 0.875rem; }
}

/* ---------- Pantallas bajas (teléfono apaisado, zoom 200 %) ----------
   Va después del bloque móvil para ganarle. El cierre se compacta para caber bajo el logo
   (intro-marca.js baja el tope del logo a 106 px): logo más chico en px enteros y respaldos
   en fila. */
@media (max-height: 520px) {
  .intro { --logo-w: 256px; }
  .intro__lema { font-size: 1.125rem; }
  .intro__respaldos { flex-direction: row; align-items: flex-end; gap: 8px 32px; margin-top: 14px; }
  .intro__respaldos li:first-child img { height: 28px; }
  .intro__respaldos li:last-child img { height: 22px; }
  .intro__firma { margin-top: 10px; }
}
/* Cierre compacto (zoom al 300–400 %: 480×300, 320×256). intro-marca.js mide si el cierre cabe
   bajo el logo y, si no, pone data-cierre: 1 = logo de 192 px, lema y respaldos más chicos
   (respaldos en fila); 2 = logo de 160 px, respaldos solo con su texto y la sigla más cerca del
   logo. Los huecos (14 y 12 px; sigla a 28 px) son los que usa intro-marca.js (CIERRE). */
.intro[data-cierre] { --logo-w: 192px; }
.intro[data-cierre] .intro__cierre { top: calc(var(--logo-y) + var(--logo-h) + 14px); }
.intro[data-cierre] .intro__lema { font-size: 1rem; }
.intro[data-cierre] .intro__respaldos { flex-direction: row; align-items: flex-end; gap: 6px 24px; margin-top: 10px; }
.intro[data-cierre] .intro__respaldos li { gap: 6px; font-size: 0.8125rem; }
.intro[data-cierre] .intro__respaldos li:first-child img { height: 22px; }
.intro[data-cierre] .intro__respaldos li:last-child img { height: 17px; }
.intro[data-cierre] .intro__firma { margin-top: 8px; font-size: 0.8125rem; }
.intro[data-cierre="2"] { --logo-w: 160px; }
.intro[data-cierre="2"][data-tono="claro"] .intro__sigla { top: calc(var(--logo-y) - 28px); }
.intro[data-cierre="2"] .intro__cierre { top: calc(var(--logo-y) + var(--logo-h) + 12px); }
.intro[data-cierre="2"] .intro__respaldos { align-items: flex-start; gap: 4px 16px; margin-top: 8px; }
.intro[data-cierre="2"] .intro__respaldos img { display: none; }
.intro[data-cierre="2"] .intro__respaldos li { font-size: 0.75rem; }
.intro[data-cierre="2"] .intro__firma { margin-top: 6px; font-size: 0.75rem; }

/* ---------- Versión sin movimiento (movimiento reducido, sin WebGL, ?sin3d=1) ----------
   Cuadros con fundidos de opacidad (WAAPI desde intro-marca.js), sin desplazamientos. Todo
   queda en su sitio; solo cambia qué se ve. Los pasos llevan un cuadro fijo de la historia (o un
   icono de la marca) y su título: intro-marca.js los ubica con --figura-* y --pasos-* (imagen
   arriba y texto abajo, o imagen a la izquierda y texto a la derecha en pantallas apaisadas
   bajas), acotados por alto: nada queda bajo el borde. */
.intro--reducida .intro__escena,
.intro--reducida .intro__barrido { display: none; }
.intro--reducida { --placa-top: calc(44vh - var(--placa-alto) / 2); }
.intro__palabra {
  position: absolute;
  z-index: 1;
  top: var(--placa-top);
  left: 0;
  right: 0;
  display: flex;
  width: max-content;
  height: var(--placa-alto);
  margin-inline: auto;
  padding: 0 0.3em;
  font-size: var(--nombre-fs);
  background: var(--placa-fondo);
  border-radius: 0.2em;
  box-shadow: 0 0 0 1px rgba(61, 200, 217, 0.3);
  opacity: 0;
}
.intro__palabra img { height: 100%; width: auto; max-width: none; }
.intro--reducida .intro__sigla { top: calc(var(--placa-top) + var(--placa-alto) + 22px); }
.intro__figura {
  position: absolute;
  z-index: 1;
  left: var(--figura-x, 0);
  top: var(--figura-y, 0);
  width: var(--figura-w, 0);
  height: calc(var(--figura-w, 0px) * 0.8);
}
/* Perfil del paciente durante el nombre (bajo la sigla, o a la izquierda de la placa en pantallas
   apaisadas bajas): intro-marca.js fija --nombre-x/-y/-w (ancho 0 si no cabe). */
.intro__figura--nombre {
  left: var(--nombre-x, 0);
  top: var(--nombre-y, 0);
  width: var(--nombre-w, 0);
  height: calc(var(--nombre-w, 0px) * 0.8);
}
.intro__cuadro {
  position: absolute;
  inset: 0;
  opacity: 0;
}
.intro__lienzo-fijo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Iconos de la marca (sin WebGL): con su proporción, centrados y dentro de la figura; llevan su
   propia placa clara (el abierto, cuadrado, se redondea como los otros dos). */
.intro__icono {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  max-width: 88%;
  max-height: 88%;
  margin: auto;
  border-radius: 12%;
}

/* ==========================================================================
   Tarjeta del hero: los 4 pasos en 3D · también al final, después de la intro
   ========================================================================== */

/* Tarjeta del hero (visor3d.js con pasos3d.js; sin tarjeta visible desde el 2026-09-30). La
   sección «Visor 3D: la demostración integrada al hero» (más arriba) da el lienzo, el póster, el
   botón, los pasos y el pie; aquí va lo que agrega el 3D: el alto reservado del botón mientras
   carga, el relevo póster → 3D (y con la intro de marca) y el alto del lienzo por tamaño de
   pantalla. Todo sobre la página clara: controles y escena (tema «heroe») en azul profundo. */

/* Mientras carga el 3D, el botón guarda su alto (invisible e inerte): el visor no salta al
   mostrarlo. Sin 3D, el módulo marca .visor3d--sin3d y el hueco se libera. */
.js .visor:not(.visor3d--sin3d) [data-visor-controles][hidden] {
  display: flex !important;
  visibility: hidden;
  opacity: 0;
}

/* ==========================================================================
   Relevo póster → 3D, y con la intro de marca
   ========================================================================== */
/* El canvas aparece sobre el póster y el póster se retira después. */
.visor__lienzo > .visor3d-canvas {
  opacity: 0;
  transition: opacity 0.5s ease;
}
.visor3d--listo .visor__lienzo > .visor3d-canvas { opacity: 1; }
.visor__lienzo > .visor__poster { transition: opacity 0.35s ease; }
.visor3d--listo .visor__lienzo > .visor__poster { opacity: 0; }

/* Durante la intro el lienzo queda vacío: la intro condensa ahí su isotipo. En el cuadro del
   aterrizaje (.visor3d--relevo) el canvas aparece sin transición. */
.visor--esperando-intro .visor__lienzo > * {
  opacity: 0 !important;
  transition: none !important;
}
.visor3d--relevo .visor__lienzo > * { transition: none !important; }

/* Escritorio bajo (hasta 1079 px de alto: 1536×864, 1440×900, 1366×768…): botones y números de
   32 px y márgenes menores, para que el hero quepa en la primera pantalla. */
@media (min-width: 1100px) and (max-height: 1079px) {
  .visor { --paso-tam: 32px; --presentacion-alto: 32px; }
  .visor__reproducir { min-height: 32px; }
  .visor__texto { margin-top: 8px; }
  .js .visor__texto { padding-block: 8px; }
  .visor__pie { margin-top: 8px; }
}

/* ---------- Escritorio: la demostración manda (2026-09-30) ----------
   Segunda iteración: el visor ya no mide lo mismo que el texto. Su lienzo toma el alto que deja la
   primera pantalla (menos el encabezado, los márgenes del hero y los controles: 330 px en total)
   entre 360 y 620 px (680 desde 1600, 760 desde 2000), redondeado a px enteros para que el canvas
   no se reescale, y el texto se centra en vertical a su lado. La escena gana tamaño sin que el hero
   pase del pliegue. pasos3d.js sigue el lienzo con su ResizeObserver y la intro lee su rectángulo
   al aterrizar (el lienzo entero debe verse en la primera pantalla), así que el relevo sigue exacto.
   Columnas 6 + 6. El título va en 4 líneas, «Cirugía oncológica / de precisión: / trazabilidad 3D
   de márgenes / en tiempo real.»: el tramo en azul empieza línea (bloque) y la línea más larga,
   «trazabilidad 3D de márgenes» (13,07em), manda el tamaño: 7,5 % del ancho de la columna (cqi;
   la columna es contenedor de consultas), hasta 56 px (72 px desde 2000). vh antes de svh. */
@media (min-width: 1100px) {
  .hero__rejilla { align-items: center; }
  .hero__texto { container-type: inline-size; }
  .hero__titulo { font-size: min(3.5rem, 7.5cqi); max-width: 13.3em; }
  .hero__titulo .acento { display: block; }
  .visor { --lienzo-max: 620px; }
  .visor__lienzo {
    aspect-ratio: auto;
    height: clamp(360px, 100vh - 330px, var(--lienzo-max));
    height: round(clamp(360px, 100svh - 330px, var(--lienzo-max)), 1px);
  }
  .visor__poster { width: auto; max-width: min(46%, 260px); max-height: 60%; }
}
/* Desde 1600 px: el mismo espacio entre columnas que .rejilla-2 (72 px), la bajada y el CTA un poco
   más grandes y un lienzo que puede crecer más. */
@media (min-width: 1600px) {
  .hero__rejilla { --hueco-columnas: clamp(32px, 5vw, 72px); }
  .visor { --lienzo-max: 680px; }
  .hero__sub { font-size: clamp(1.1875rem, 0.5rem + 0.75vw, 1.3125rem); }
  .hero__acciones .btn { min-height: 56px; padding-inline: 28px; font-size: 1.0625rem; }
}
/* Sobre 2000 px el contenedor vuelve a crecer (ver :root) y el hero crece con él: el título puede
   pasar de 56 px (hasta 72), la bajada y el CTA también. */
@media (min-width: 2000px) {
  .hero__titulo { font-size: min(4.5rem, 7.5cqi); }
  .visor { --lienzo-max: 760px; }
  .hero__sub { font-size: clamp(1.3125rem, 0.714vw + 7.7px, 1.5625rem); }
  .hero__acciones .btn {
    min-height: clamp(56px, 56px + (100vw - 2000px) * 0.0143, 64px);
    padding-inline: clamp(28px, 28px + (100vw - 2000px) * 0.0072, 32px);
    font-size: clamp(1.0625rem, 17px + (100vw - 2000px) * 0.00357, 1.1875rem);
  }
}

/* Tableta apaisada (1024×768, 1080×810…): el visor va bajo el texto; el lienzo mide el alto que deja
   la ventana bajo el encabezado y sobre los controles (entre 360 y 600 px) y conserva todo el
   ancho, así el visor entero cabe en una pantalla al llegar a él. La proporción queda bajo 2,2 (a
   1024×768, 944×568), así que el encuadre nunca pasa al «bajo». Bajo 561 px de alto manda la regla
   siguiente. vh antes de svh. */
@media (min-width: 700px) and (max-width: 1099px) and (min-height: 561px) and (orientation: landscape) {
  .visor__lienzo {
    aspect-ratio: auto;
    height: clamp(360px, 100vh - 200px, 600px);
    height: round(clamp(360px, 100svh - 200px, 600px), 1px);
  }
}
/* Bajo 1000 px de ancho la barra fija de contacto (72 px) también descuenta. */
@media (min-width: 700px) and (max-width: 999px) and (min-height: 561px) and (orientation: landscape) {
  .visor__lienzo {
    height: clamp(300px, 100vh - 280px, 600px);
    height: round(clamp(300px, 100svh - 280px, 600px), 1px);
  }
}

/* Pantalla apaisada y baja (teléfono girado, zoom al 200 %): el lienzo no pasa del alto útil
   de la ventana, bajo el encabezado y sobre la barra fija de contacto (mínimo 170 px). El encuadre
   del hero nunca corta la cabeza, así que la escena se achica para caber entera.
   El póster (sin 3D o mientras carga) mide como mucho el 60 % de ese alto, como en escritorio: el
   lienzo ya no recorta (2026-09-30) y a su ancho (260 px) pasaba del lienzo y tapaba la barra de
   controles (a 844×390, 258 px de póster en 220 de lienzo). El tope va en la misma fórmula del
   alto, no en %: la fila de la grilla crecería con el póster y el % no lo frenaría. */
@media (max-width: 1099px) and (max-height: 560px) and (orientation: landscape) {
  .visor__lienzo {
    aspect-ratio: auto;
    height: clamp(170px, calc(100vh - 170px), 340px);
    height: clamp(170px, calc(100svh - 170px), 340px);
  }
  .visor__poster {
    width: auto;
    max-width: min(46%, 260px);
    max-height: clamp(102px, calc(60vh - 102px), 204px);
    max-height: clamp(102px, calc(60svh - 102px), 204px);
  }
}

/* ==========================================================================
   Móvil: blancos táctiles de 44 px
   ========================================================================== */
@media (max-width: 699px) {
  /* «Ver presentación» también a 44 px (su lugar ya queda guardado mientras está oculto). */
  .visor__presentacion,
  .visor__reproducir {
    min-height: 44px;
    padding: 8px 14px;
  }
  .visor { --paso-tam: 44px; }
  .hero__fondo-pausa { bottom: 0; width: 44px; height: 44px; }
  /* El pie mide al menos lo que el botón: entre 590 y 699 px cabe en un renglón y el botón, anclado
     abajo, quedaba sobre «Ver presentación». */
  .js .visor__pie { padding-right: 52px; min-height: 44px; }
}

/* Colores forzados (alto contraste): la escena del visor está pensada para el blanco frío (trazos
   y rótulos en azul profundo); el lienzo conserva ese fondo para que siga legible sobre un fondo de
   sistema oscuro. Las muestras de la leyenda (fondo y contorno) también conservan sus colores. */
@media (forced-colors: active) {
  .visor__lienzo { forced-color-adjust: none; background: #F7FAFC; }
  .leyenda__muestra { forced-color-adjust: none; }
  /* El paso activo sigue distinguible cuando el sistema sustituye los rellenos. */
  .visor__paso[aria-current="step"] { border: 4px double ButtonText; }
  /* Solo el icono conserva su pintura; el boton usa los colores del sistema. */
  .visor__reproducir::before { forced-color-adjust: none; color: ButtonText; }
  /* El fondo animado es un canvas (el sistema no lo sustituye): se quita, con su botón. */
  .hero__fondo, .hero__fondo-pausa { display: none; }
}
@media print {
  .hero__fondo, .hero__fondo-pausa { display: none; }
}

/* ==========================================================================
   Módulo: Tarjetas de la solución (solucion.js)
   ========================================================================== */
/* Acordeón de «02 / La solución» (pedido de Manuel, 2026-09-29, a partir de las «tarjetas que se
   expanden»): siempre hay una tarjeta abierta y las demás cerradas; cambian solo cuando la persona
   pincha. Desde 1100 px, en fila: la abierta, ancha y blanca, con su texto a la izquierda y la
   ilustración entera a la derecha; las cerradas son franjas con número, miniatura, nombre corto y
   «+». En tableta y móvil, en columna: filas con miniatura, número, título y «+», y la abierta con
   su ilustración y su texto debajo.
   Rige con html.solucion-acordeon, que el <head> pone antes del primer pintado (y quita si el
   módulo no llega), y solo en pantalla: al imprimir queda la grilla. Se animan el ancho (en fila)
   o el alto (en columna) de las tarjetas, en 0,38 s desde el clic o la tecla (dentro de los 500 ms
   que no cuentan como desplazamiento de diseño), y transform/opacity; con movimiento reducido,
   nada. El botón que solucion.js pone en cada título repite la disposición del h3: insertarlo no
   mueve nada (probar-solucion.py, boton-no-mueve). */
@media screen {
  .solucion-acordeon .tarjetas {
    --hueco: 16px;
    --sol-curva: cubic-bezier(0.05, 0.61, 0.41, 0.95);   /* la del ejemplo de Manuel */
    --sol-salida: cubic-bezier(0.2, 0.7, 0.2, 1);
    --sol-dur: 0.38s;
    gap: var(--hueco);
  }
  .solucion-acordeon .tarjeta {
    padding: 0;
    overflow: clip;
    cursor: pointer;
  }
  .solucion-acordeon .tarjeta.is-abierta { background: var(--white); cursor: auto; }
  .solucion-acordeon .tarjeta:nth-child(2) { --i: 1; }
  .solucion-acordeon .tarjeta:nth-child(3) { --i: 2; }
  .solucion-acordeon .tarjeta:nth-child(4) { --i: 3; }
  /* Barra azul de la abierta: un borde, que el modo de alto contraste conserva. */
  .solucion-acordeon .tarjeta::after {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    border-top: 3px solid var(--action-primary);
    opacity: 0;
    pointer-events: none;
  }
  .solucion-acordeon .tarjeta.is-abierta::after { opacity: 1; }

  .solucion-acordeon .tarjeta__titulo,
  .solucion-acordeon .tarjeta__boton { order: 0; display: flex; min-width: 0; }
  .solucion-acordeon .tarjeta__boton { flex: 1 1 auto; cursor: inherit; }
  /* La tarjeta cerrada entera es su botón; en la abierta no, así su texto se puede seleccionar. */
  .solucion-acordeon .tarjeta:not(.is-abierta) .tarjeta__boton::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
  }
  /* El anillo de foco rodea la tarjeta (el del botón lo cortaría el overflow de la tarjeta). Solo
     donde hay :has(): sin él (p. ej. Firefox 115 ESR) el botón conserva su propio anillo. */
  @supports selector(:has(a)) {
    .solucion-acordeon .tarjeta__boton:focus-visible { outline: none; }
    .solucion-acordeon .tarjeta:has(.tarjeta__boton:focus-visible) {
      outline: 2px solid var(--focus);
      outline-offset: 2px;
    }
  }
  /* El número en un círculo (el ícono redondo del ejemplo): blanco en las cerradas, azul en la abierta. */
  .solucion-acordeon .tarjeta__num {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 2.5rem;
    height: 2.5rem;
    margin: 0;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--white);
    font-size: 0.875rem;
    letter-spacing: 0.02em;
    line-height: 1;
  }
  .solucion-acordeon .is-abierta .tarjeta__num {
    background: var(--action-primary);
    border-color: var(--action-primary);
    color: var(--white);
  }
  .solucion-acordeon .tarjeta__nombre { display: block; min-width: 0; }
  .solucion-acordeon .tarjeta__cuerpo,
  .solucion-acordeon .tarjeta__cuerpo-in { display: block; }
  .solucion-acordeon .tarjeta__marco { margin: 0; }
  .solucion-acordeon .tarjeta__cuerpo-in > p { margin: 0; }
  .solucion-acordeon .tarjeta__portada { pointer-events: none; }
  .solucion-acordeon .tarjeta__mini { height: auto; aspect-ratio: 1; }
  /* Parallax: solucion.js da --px y --py (de -1 a 1) con el mouse sobre la abierta. */
  .solucion-acordeon .tarjeta__marco {
    transform: translate(calc(var(--px, 0) * 6px), calc(var(--py, 0) * 6px));
  }
  /* Primera vista: lo que va a entrar espera invisible (solo si la lista estaba fuera de pantalla). */
  .solucion-acordeon [data-solucion-espera] .is-abierta :is(.tarjeta__num, .tarjeta__nombre, .tarjeta__img),
  .solucion-acordeon [data-solucion-espera] .is-abierta .tarjeta__cuerpo-in > p,
  .solucion-acordeon [data-solucion-espera] .tarjeta__mini { opacity: 0; }
  /* Cambio sin transición (compensación en columna y cambio de disposición). */
  .solucion-acordeon .tarjeta.sin-transicion,
  .solucion-acordeon .tarjeta.sin-transicion * { transition: none !important; }
}

/* ---------- En fila (desde 68,75em: 1100 px con letra de 16 px) ---------- */
/* Anchos con unidades de contenedor: las franjas miden --tira y la abierta --abierta (lo que queda),
   así las dos tarjetas que cambian suman siempre lo mismo. El texto de la abierta tiene ancho fijo
   (no se reacomoda mientras la tarjeta crece) y la ilustración va en su lugar final: la tarjeta la
   descubre al crecer. El alto es el de la ilustración más el relleno: igual con cualquier abierta.
   El corte en em se corre con la letra del navegador, y la ilustración cede antes que el texto: el
   texto nunca baja de --texto-min, así que la ilustración nunca lo tapa. */
@media screen and (min-width: 68.75em) {
  .solucion-acordeon .tarjetas {
    --tira: clamp(7.5rem, 7vw, 9rem);
    --pad: 28px;
    --texto-min: 15rem;
    --abierta: calc(100cqi - 3 * (var(--tira) + var(--hueco)));
    --img: max(10rem, min(clamp(16.5rem, 23vw, 25rem), calc(var(--abierta) - 3 * var(--pad) - 2px - var(--texto-min))));
    --texto: min(34rem, calc(var(--abierta) - 3 * var(--pad) - var(--img) - 2px));
    display: flex;
    container-type: inline-size;
  }
  .solucion-acordeon .tarjeta {
    flex: 0 1 var(--tira);
    min-width: 0;
    min-height: calc(var(--img) + 2 * var(--pad));
    align-items: center;
    justify-content: flex-start;
    padding: 20px 0 0;
  }
  .solucion-acordeon .tarjeta.is-abierta {
    flex-basis: var(--abierta);
    align-items: flex-start;
    justify-content: center;
    padding: var(--pad);
  }
  .solucion-acordeon .tarjeta__titulo,
  .solucion-acordeon .tarjeta__boton {
    flex-direction: column;
    align-items: center;
    gap: 14px;
  }
  .solucion-acordeon .tarjeta__titulo { width: 100%; }
  .solucion-acordeon .is-abierta .tarjeta__titulo {
    width: var(--texto);
    font-size: 1.375rem;
    line-height: 1.22;
  }
  .solucion-acordeon .is-abierta .tarjeta__titulo,
  .solucion-acordeon .is-abierta .tarjeta__boton { align-items: flex-start; }
  /* En la franja, el nombre completo lo lee el lector de pantalla; a la vista va el corto. */
  .solucion-acordeon .tarjeta:not(.is-abierta) .tarjeta__nombre {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  /* Miniatura y nombre corto, centrados entre el número (arriba) y el «+» (abajo). */
  .solucion-acordeon .tarjeta__portada {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: calc(20px + 2.5rem + 12px) 10px calc(18px + 1.5rem + 12px);
    text-align: center;
  }
  .solucion-acordeon .tarjeta.is-abierta .tarjeta__portada { display: none; }
  .solucion-acordeon .tarjeta__mini { width: min(calc(var(--tira) - 2rem), 100%); border-radius: 10px; }
  .solucion-acordeon .tarjeta__corto {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.875rem;
    line-height: 1.25;
    color: var(--brand-primary);
    overflow-wrap: break-word;
  }
  /* «+»: la franja se abre. */
  .solucion-acordeon .tarjeta__portada::after {
    content: "";
    position: absolute;
    bottom: 18px;
    left: calc(50% - 0.75rem);
    width: 1.5rem;
    height: 1.5rem;
    border: 1px solid var(--border-control);
    border-radius: 50%;
    background:
      linear-gradient(var(--action-primary), var(--action-primary)) center / 10px 2px no-repeat,
      linear-gradient(var(--action-primary), var(--action-primary)) center / 2px 10px no-repeat,
      var(--white);
  }
  .solucion-acordeon .tarjeta:not(.is-abierta) .tarjeta__cuerpo { display: none; }
  .solucion-acordeon .is-abierta .tarjeta__cuerpo { width: var(--texto); margin-top: 12px; }
  .solucion-acordeon .tarjeta__cuerpo-in > p { font-size: 1rem; color: var(--text-secondary); }
  .solucion-acordeon .tarjeta__marco {
    position: absolute;
    top: calc(50% - var(--img) / 2);
    left: calc(var(--abierta) - 2px - var(--pad) - var(--img));
    width: var(--img);
  }
}
@media screen and (min-width: 68.75em) and (prefers-reduced-motion: no-preference) {
  .solucion-acordeon .tarjeta {
    transition: flex-basis var(--sol-dur) var(--sol-curva), background-color 0.2s ease, border-color 0.2s ease;
  }
}

/* ---------- En columna (tableta y móvil) ---------- */
/* Cada tarjeta es una rejilla: miniatura | título y «+»; debajo, el cuerpo, que se abre de 0fr a 1fr
   (su alto real) y se esconde con visibility cuando termina de cerrarse. La abierta deja la
   miniatura: su ilustración va grande en el cuerpo. */
@media screen and (max-width: 68.74em) {
  .solucion-acordeon .tarjetas {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .solucion-acordeon .tarjeta {
    display: grid;
    grid-template-columns: 3.5rem minmax(0, 1fr);
    grid-template-rows: auto 0fr;
    grid-template-areas: "portada titulo" "cuerpo cuerpo";
    column-gap: 14px;
    align-items: center;
    /* Mientras el cuerpo pasa de 0fr a 1fr, el alto de la tarjeta puede ir por delante de sus filas:
       ese sobrante queda abajo, no en la fila del título (que si no se correría hacia abajo). */
    align-content: start;
    padding: 12px 16px 12px 12px;
  }
  .solucion-acordeon .tarjeta.is-abierta {
    grid-template-rows: auto 1fr;
    grid-template-areas: "titulo titulo" "cuerpo cuerpo";
    padding: 12px 16px 20px;
  }
  .solucion-acordeon .tarjeta__portada { grid-area: portada; display: block; }
  .solucion-acordeon .tarjeta.is-abierta .tarjeta__portada { display: none; }
  .solucion-acordeon .tarjeta__mini { width: 3.5rem; border-radius: 8px; }
  .solucion-acordeon .tarjeta__corto { display: none; }
  .solucion-acordeon .tarjeta__titulo {
    grid-area: titulo;
    align-items: center;
    gap: 12px;
    min-height: 2.75rem;
    font-size: 1.0625rem;
    line-height: 1.3;
  }
  .solucion-acordeon .tarjeta__boton { align-items: center; gap: 12px; }
  .solucion-acordeon .tarjeta__nombre { flex: 1 1 auto; }
  /* «+» en las cerradas, «−» en la abierta. */
  .solucion-acordeon .tarjeta__titulo::after {
    content: "";
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    border: 1px solid var(--border-control);
    border-radius: 50%;
    background:
      linear-gradient(var(--action-primary), var(--action-primary)) center / 10px 2px no-repeat,
      linear-gradient(var(--action-primary), var(--action-primary)) center / 2px 10px no-repeat,
      var(--white);
  }
  .solucion-acordeon .is-abierta .tarjeta__titulo::after {
    background:
      linear-gradient(var(--action-primary), var(--action-primary)) center / 10px 2px no-repeat,
      var(--white);
  }
  .solucion-acordeon .tarjeta__cuerpo {
    grid-area: cuerpo;
    align-self: stretch;
    min-height: 0;
    overflow: hidden;
    visibility: hidden;
  }
  .solucion-acordeon .is-abierta .tarjeta__cuerpo { visibility: visible; }
  .solucion-acordeon .tarjeta__cuerpo-in {
    display: grid;
    justify-items: center;
    gap: 14px;
    padding-top: 14px;
  }
  .solucion-acordeon .tarjeta__marco { width: min(18.75rem, 100%); }
  .solucion-acordeon .tarjeta__cuerpo-in > p { justify-self: stretch; }
}
/* Teléfonos angostos: el número va sobre el nombre, así «Interoperabilidad» cabe junto a la
   miniatura. El h3 y el botón comparten la rejilla (número y nombre en dos filas, «+» a la
   derecha): con o sin botón, cada cosa queda en su lugar. */
@media screen and (max-width: 24.9375em) {
  .solucion-acordeon .tarjeta { grid-template-columns: 3.25rem minmax(0, 1fr); column-gap: 12px; }
  .solucion-acordeon .tarjeta__mini { width: 3.25rem; }
  .solucion-acordeon .tarjeta__titulo {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 10px;
    row-gap: 6px;
    font-size: 1rem;
  }
  .solucion-acordeon .tarjeta__titulo > .tarjeta__num { grid-area: 1 / 1; justify-self: start; }
  .solucion-acordeon .tarjeta__titulo > .tarjeta__nombre { grid-area: 2 / 1; }
  .solucion-acordeon .tarjeta__titulo::after { grid-area: 1 / 2 / 3 / 3; }
  .solucion-acordeon .tarjeta__boton {
    grid-area: 1 / 1 / 3 / 2;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }
  .solucion-acordeon .tarjeta__num { width: 2.25rem; height: 2.25rem; align-self: flex-start; }
}
@media screen and (max-width: 68.74em) and (prefers-reduced-motion: no-preference) {
  .solucion-acordeon .tarjeta {
    transition: grid-template-rows var(--sol-dur) var(--sol-curva), background-color 0.2s ease, border-color 0.2s ease;
  }
  .solucion-acordeon .tarjeta__cuerpo { transition: visibility 0s linear var(--sol-dur); }
  .solucion-acordeon .is-abierta .tarjeta__cuerpo { transition-delay: 0s; }
}

/* ---------- Alto contraste (forced-colors) ---------- */
/* Los degradados desaparecen: «+» y «−» pasan a ser signos de texto, y el número de la abierta se
   distingue por su borde (el relleno azul se pierde). */
@media screen and (forced-colors: active) {
  .solucion-acordeon .is-abierta .tarjeta__num { border-width: 3px; }
}
@media screen and (min-width: 68.75em) and (forced-colors: active) {
  .solucion-acordeon .tarjeta__portada::after {
    content: "+";
    display: grid;
    place-items: center;
    font: 700 1.125rem/1 var(--font-display);
  }
}
@media screen and (max-width: 68.74em) and (forced-colors: active) {
  .solucion-acordeon .tarjeta__titulo::after {
    content: "+";
    display: grid;
    place-items: center;
    font: 700 1.125rem/1 var(--font-display);
  }
  .solucion-acordeon .is-abierta .tarjeta__titulo::after { content: "\2212"; }
}

/* ---------- Mouse: la franja se destaca (sin cambiar anchos) ---------- */
@media screen and (hover: hover) and (pointer: fine) {
  .solucion-acordeon .tarjeta:not(.is-abierta):hover {
    background: var(--white);
    border-color: var(--action-primary);
  }
  .solucion-acordeon .tarjeta:not(.is-abierta):hover .tarjeta__num { border-color: var(--action-primary); }
  .solucion-acordeon .tarjeta:not(.is-abierta):hover .tarjeta__mini { transform: translateY(-4px); }
}

/* ---------- Coreografía: al abrir y en la primera vista ([data-anima], solucion.js) ---------- */
/* Solo transform y opacity. «backwards»: esperan en su primer cuadro y al terminar no fijan nada,
   así el realce del mouse sigue funcionando. */
@media screen and (prefers-reduced-motion: no-preference) {
  .solucion-acordeon .tarjeta__mini { transition: transform 0.25s var(--sol-salida); }
  .solucion-acordeon .tarjeta__marco { transition: transform 0.35s ease-out; }
  .solucion-acordeon .tarjeta[data-anima].is-abierta .tarjeta__num { animation: sol-rebota 0.5s var(--sol-salida) backwards; }
  .solucion-acordeon .tarjeta[data-anima].is-abierta .tarjeta__nombre { animation: sol-desliza 0.45s var(--sol-salida) 0.08s backwards; }
  .solucion-acordeon .tarjeta[data-anima].is-abierta .tarjeta__cuerpo-in > p { animation: sol-desliza 0.45s var(--sol-salida) 0.16s backwards; }
  .solucion-acordeon .tarjeta[data-anima].is-abierta .tarjeta__img { animation: sol-asienta 0.55s var(--sol-salida) 0.1s backwards; }
  .solucion-acordeon .tarjeta[data-anima]:not(.is-abierta) .tarjeta__mini {
    animation: sol-sube 0.5s var(--sol-salida) calc(0.12s + var(--i, 0) * 0.07s) backwards;
  }
}
@keyframes sol-rebota {
  0% { opacity: 0; transform: scale(0.6); }
  60% { opacity: 1; transform: scale(1.08); }
  100% { opacity: 1; transform: none; }
}
@keyframes sol-desliza { from { opacity: 0; transform: translateX(-14px); } }
@keyframes sol-asienta { from { opacity: 0; transform: scale(0.94); } }
@keyframes sol-sube { from { opacity: 0; transform: translateY(12px); } }

/* ==========================================================================
   Módulo: franja de respaldos (respaldos.js)
   ========================================================================== */
/* Cinta (bajo 700 px, con respaldos.js y sin movimiento reducido): la pista lleva el juego de
   celdas y su copia (aria-hidden, inert); correrla la mitad de su ancho es exactamente un juego
   (cada juego termina con su aire), así la vuelta no tiene costura. respaldos.js fija --cinta-dur
   (unos 30 px por segundo) y data-cinta: «corre», «quieta» (mouse, foco, dedo, fuera de pantalla
   o pestaña oculta) o «pausada» (con «Pausar»: se desliza con el dedo, así se llega a todas las
   celdas). La animación se declara solo sin movimiento reducido: la regla global de movimiento
   reducido la dejaría en su último cuadro. */
@media (max-width: 699px) {
  .respaldos[data-cinta] .respaldos__ventana {
    overflow: hidden;
    scroll-snap-type: none;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--gutter), #000 calc(100% - var(--gutter)), transparent);
            mask-image: linear-gradient(to right, transparent, #000 var(--gutter), #000 calc(100% - var(--gutter)), transparent);
  }
  .respaldos[data-cinta] .respaldos__ventana::-webkit-scrollbar { display: none; }
  .respaldos[data-cinta="pausada"] .respaldos__ventana { overflow-x: auto; overflow-y: hidden; }
}
@media (max-width: 699px) and (prefers-reduced-motion: no-preference) {
  .respaldos[data-cinta] .respaldos__pista {
    animation: respaldos-cinta var(--cinta-dur, 45s) linear infinite;
    will-change: transform;
  }
  .respaldos[data-cinta="quieta"] .respaldos__pista,
  .respaldos[data-cinta="pausada"] .respaldos__pista { animation-play-state: paused; }
}
@keyframes respaldos-cinta { to { transform: translate3d(-50%, 0, 0); } }

/* «Pausar» / «Reanudar» (WCAG 2.2.2): 44 px de alto, antes de la cinta en el orden de lectura. */
.respaldos__pausa {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 14px;
  background: transparent;
  color: var(--brand-primary);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-control);
  font: 600 0.875rem/1 var(--font-display);
  cursor: pointer;
  margin-bottom: 14px;
}
.respaldos__pausa::before {       /* ‖: dos barras de 3 px con 4 px entre ellas (border-box) */
  content: "";
  width: 10px;
  height: 12px;
  border-inline: 3px solid currentColor;
}
.respaldos__pausa[data-modo="reanudar"]::before {   /* ▶ */
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 6px 0 6px 10px;
  border-color: transparent transparent transparent currentColor;
}
@media (hover: hover) and (pointer: fine) {
  .respaldos__pausa:hover { background: rgba(16, 43, 70, 0.06); }
}
@media (forced-colors: active) {
  .respaldos__pausa::before { display: none; }   /* queda el texto */
}

/* Globos (desde 700 px, con respaldos.js): debajo de la celda (arriba taparían el rótulo de su
   mitad), azul profundo con texto Inter blanco. --globo-dx lo corre para que no salga de la
   ventana, y la flecha sigue en el centro de la celda. ::before tiende un puente sobre el hueco:
   el mouse pasa de la celda al globo sin cerrarlo (WCAG 1.4.13). data-globo en la celda: «abajo»
   o «arriba» (si abajo no cabe en la ventana). Sin JavaScript no hay globos: el dato está en la
   sección Evidencia. */
.respaldos__globo { display: none; }
@media (min-width: 700px) {
  [data-respaldos-listo] .respaldos__globo {
    display: block;
    position: absolute;
    z-index: 5;
    left: 50%;
    top: calc(100% + 8px);
    width: max-content;
    max-width: min(18rem, calc(100vw - 16px));
    padding: 8px 12px;
    border: 1px solid transparent;    /* se ve en colores forzados */
    border-radius: var(--radius-control);
    background: var(--brand-primary);
    color: var(--white);
    font: 500 0.8125rem/1.4 var(--font-text);
    text-align: left;
    text-wrap: pretty;
    box-shadow: 0 6px 18px rgba(16, 43, 70, 0.18);
    transform: translate(calc(-50% + var(--globo-dx, 0px)), -4px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease, visibility 0s linear 0.15s;
  }
  [data-respaldos-listo] .respaldos__globo::after {   /* flecha */
    content: "";
    position: absolute;
    bottom: 100%;
    left: calc(50% - var(--globo-dx, 0px));
    width: 10px;
    height: 10px;
    background: inherit;
    transform: translate(-50%, 50%) rotate(45deg);
  }
  [data-respaldos-listo] .respaldos__globo::before {  /* puente sobre el hueco */
    content: "";
    position: absolute;
    inset: auto 0 100%;
    height: 10px;
  }
  [data-respaldos-listo] .confianza__item[data-globo] .respaldos__globo {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translate(calc(-50% + var(--globo-dx, 0px)), 0);
    transition-delay: 0s;
  }
  [data-respaldos-listo] .confianza__item[data-globo="arriba"] .respaldos__globo { top: auto; bottom: calc(100% + 8px); }
  [data-respaldos-listo] .confianza__item[data-globo="arriba"] .respaldos__globo::after {
    bottom: auto;
    top: 100%;
    transform: translate(-50%, -50%) rotate(45deg);
  }
  [data-respaldos-listo] .confianza__item[data-globo="arriba"] .respaldos__globo::before { inset: 100% 0 auto; }
}
@media print {
  .respaldos__globo, .respaldos__pausa, [data-respaldos-copia] { display: none !important; }
  .respaldos__pista { animation: none !important; transform: none !important; width: auto !important; }
  .respaldos__ventana {
    overflow: visible !important;
    margin-inline: 0 !important;
    padding-inline: 0 !important;
    -webkit-mask-image: none !important;
            mask-image: none !important;
  }
  .respaldos__juego, .respaldos__grupo, .confianza { flex-wrap: wrap; }
}

/* ==========================================================================
   Módulo: presentación en video (explicador.js; pedido de Manuel, 2026-10-22)
   Botón secundario del hero, bloque de la sección 02 (portada, capítulos, llamados y créditos) y
   ventana flotante. El reproductor es uno solo: la ventana lo recibe y lo devuelve. El triángulo
   de play es SVG: el carácter no está en la Inter recortada.
   ========================================================================== */
.btn__icono { width: 12px; height: 12px; flex: none; }

/* Lo primero de la sección 02, antes de las tarjetas (pedido de Manuel, 2026-10-22): a todo el ancho
   de la página, sin espacio vacío al costado. */
.explicador { margin-bottom: clamp(48px, 6vw, 80px); }
.explicador__titulo { font-size: 1.375rem; line-height: 1.2; margin-bottom: 20px; }
.explicador__marco {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius-card);
  background: var(--brand-primary);
}
/* Por clase y no por hijo directo: sin JavaScript el <video> vive dentro del <noscript>. */
.explicador__portada,
.explicador__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.explicador__portada { display: block; color: var(--white); text-decoration: none; }
.explicador__img { width: 100%; height: 100%; object-fit: cover; }
.explicador__video { background: var(--brand-primary); }
/* El círculo contrasta sobre el blanco del cuadro y sobre la pieza violeta: azul profundo con aro
   blanco. */
.explicador__play {
  position: absolute;
  left: 50%;
  top: 50%;
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  margin: -36px 0 0 -36px;
  border-radius: 50%;
  background: var(--brand-primary);
  color: var(--white);
  box-shadow: 0 0 0 2px var(--white);
  transition: transform 0.2s ease;
}
.explicador__play svg { margin-left: 3px; }
.explicador__portada:hover .explicador__play,
.explicador__portada:focus-visible .explicador__play { transform: scale(1.06); }
.explicador__dur {
  position: absolute;
  left: 14px;
  bottom: 14px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  background: rgba(7, 29, 53, 0.78);
  color: var(--white);
  font: 600 0.8125rem/1.2 var(--font-text);
  font-variant-numeric: tabular-nums;
}
/* Foco: el anillo propio va hacia adentro (el marco recorta lo de afuera); donde hay :has(), lo
   dibuja el marco por fuera, como las tarjetas de la solución. */
.explicador__portada:focus-visible { outline: 3px solid var(--brand-primary); outline-offset: -3px; }
@supports selector(:has(a)) {
  .explicador__portada:focus-visible { outline: none; }
  .explicador__marco:has(> .explicador__portada:focus-visible) {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
  }
}
/* Subtítulos en caja azul profundo con letra blanca: el video pone sus propios rótulos en oscuro sobre
   claro, y así el subtítulo no se confunde con ellos. La letra sigue al alto del video
   (explicador.js fija --explicador-cue, con un mínimo de 14 px). Sobre el propio video: el selector
   viaja con él a la ventana flotante. */
.explicador__video::cue {
  background-color: rgba(16, 43, 70, 0.9);
  color: #FFFFFF;
  font-family: "Inter", system-ui, sans-serif;
  font-weight: 600;
  line-height: 1.22;
  font-size: var(--explicador-cue, 100%);
}
.explicador__error { margin-top: 10px; font-size: 0.9375rem; color: var(--text-secondary); }

/* Capítulos: en lista (el minuto y el título en un renglón) bajo 980 px y, desde 1200 px, al costado
   del video; entre medio, y en la ventana flotante desde 980 px, los 5 en una fila (sin uno solo
   abajo). */
.explicador__capitulos {
  list-style: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  margin-top: 16px;
}
.explicador__capitulo {
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid var(--border-control);
  border-radius: var(--radius-control);
  color: var(--brand-primary);
  font-size: 0.9375rem;
  line-height: 1.3;
  text-decoration: none;
  transition: background-color 0.18s ease, border-color 0.18s ease;
}
/* Solo con ratón: en una pantalla táctil el último capítulo tocado quedaría marcado junto al que corre. */
@media (hover: hover) {
  .explicador__capitulo:hover { background: rgba(16, 43, 70, 0.06); border-color: var(--brand-primary); }
}
.explicador__cap-t {
  flex: none;
  min-width: 2.6em;
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--action-primary);
}
@media (min-width: 980px) {
  .explicador__capitulos { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .explicador__capitulo { flex-direction: column; align-items: stretch; gap: 2px; height: 100%; }
}
.explicador__capitulo[aria-current="true"] {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--white);
}
.explicador__capitulo[aria-current="true"] .explicador__cap-t { color: var(--brand-margin); }
.explicador__acciones { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px; }
/* Desde 1200 px: el video a la izquierda y, a su derecha, los capítulos en lista arriba y los dos
   llamados al pie, alineados con el borde de abajo del video. Solo en la página: en la ventana
   flotante el reproductor sigue en columna. Más angosto, uno debajo del otro. */
@media (min-width: 1200px) {
  .explicador .explicador__reproductor {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(300px, 28%, 420px);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas: "marco capitulos" "marco acciones";
    column-gap: clamp(24px, 2.6vw, 40px);
    row-gap: 16px;
  }
  .explicador .explicador__marco { grid-area: marco; align-self: start; }
  .explicador .explicador__capitulos {
    grid-area: capitulos;
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    margin-top: 0;
  }
  .explicador .explicador__capitulo { flex-direction: row; align-items: baseline; gap: 12px; height: auto; }
  .explicador .explicador__acciones { grid-area: acciones; flex-direction: column; margin-top: 0; }
  .explicador .explicador__acciones .btn { width: 100%; }
  .explicador .explicador__error,
  .explicador .explicador__creditos { grid-column: 1 / -1; }
}
/* Celular acostado: el video de la página entra entero bajo la cabecera fija. */
@media (max-height: 500px) {
  .explicador .explicador__marco {
    width: min(100%, calc((100vh - 84px) * 16 / 9));
    width: min(100%, calc((100dvh - 84px) * 16 / 9));
    margin-inline: auto;
  }
}

.explicador__creditos {
  margin-top: 16px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--text-secondary);
}
.explicador__creditos summary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
  color: var(--brand-primary);
  cursor: pointer;
}
/* El triángulo dice que se abre (inline-flex quita el marcador propio del <summary>). */
.explicador__creditos summary::before {
  content: "";
  width: 0;
  height: 0;
  margin-right: 8px;
  border-left: 6px solid currentColor;
  border-block: 5px solid transparent;
  transition: transform 0.2s ease;
}
.explicador__creditos[open] > summary::before { transform: rotate(90deg); }
.explicador__creditos p,
.explicador__creditos ul { max-width: 80ch; margin-top: 8px; }
.explicador__creditos ul { padding-left: 1.2em; }
.explicador__creditos li + li { margin-top: 4px; }

/* Ventana flotante. Solo la caja desplaza: el <dialog> anula el overflow y el alto máximo que le da
   el navegador. Sin el centinela --explicador-modal (una hoja anterior en caché) el módulo no la
   usa y el botón del hero queda como ancla. */
/* La ventana mide lo que cabe del video a lo alto (más el relleno de la caja): así el video, los
   capítulos y los llamados tienen el mismo ancho. */
.explicador-modal {
  --explicador-modal: 1;
  width: min(1120px, calc(100vw - 32px), calc((100vh - 320px) * 16 / 9 + 32px));
  width: min(1120px, calc(100vw - 32px), calc((100dvh - 320px) * 16 / 9 + 32px));
  max-width: none;
  max-height: none;
  padding: 0;
  border: 0;
  overflow: visible;
  background: transparent;
  color: var(--text-primary);
}
.explicador-modal:not([open]) { display: none; }
.explicador-modal::backdrop { background: #071D35b3; }
.explicador-modal__caja {
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  overflow: auto;
  overscroll-behavior: contain;
  padding: 12px 16px 20px;
  border-radius: var(--radius-card);
  background: var(--white);
}
.explicador-modal__cabeza {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.explicador-modal__titulo { font-size: 1.125rem; line-height: 1.25; }
.explicador-modal__cerrar {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1.5px solid transparent;
  border-radius: 50%;
  background: transparent;
  color: var(--brand-primary);
  cursor: pointer;
}
@media (hover: hover) {
  .explicador-modal__cerrar:hover { background: rgba(16, 43, 70, 0.06); border-color: var(--brand-primary); }
}
.explicador-modal .explicador__reproductor { max-width: none; }
@media (max-width: 699px), (max-height: 500px) {
  .explicador-modal { width: 100%; height: 100vh; height: 100dvh; margin: 0; }
  .explicador-modal__caja { height: 100%; max-height: none; border-radius: 0; }
}
@media (max-height: 500px) {
  .explicador-modal__caja { padding-block: 0 12px; }
  .explicador-modal__cabeza { min-height: 44px; margin-bottom: 0; }
  .explicador-modal .explicador__marco {
    width: min(100%, calc((100vh - 56px) * 16 / 9));
    width: min(100%, calc((100dvh - 56px) * 16 / 9));
  }
}
/* Con la ventana abierta la página no se desplaza; el canal de la barra se reserva para que el
   ancho no cambie (el fondo del hero y el acordeón de la solución dependen de él). */
html.explicador-abierto { overflow: hidden; scrollbar-gutter: stable; }
/* La barra fija de abajo (móvil) taparía los controles del video. */
.explicador-a-la-vista .barra-movil { display: none !important; }

@media (max-width: 699px) {
  .explicador__play { width: 56px; height: 56px; margin: -28px 0 0 -28px; }
  .explicador__acciones .btn { width: 100%; }
}
.no-js .explicador__portada { display: none; }
@media (prefers-reduced-motion: reduce) {
  .explicador__play,
  .explicador__capitulo,
  .explicador__capitulo *,
  .explicador__creditos summary::before { transition-property: none !important; }
}

/* Alto contraste: el video y sus controles conservan sus colores (si no, la barra de controles se
   vuelve una franja opaca que tapa la imagen). */
@media (forced-colors: active) {
  .explicador__video,
  .explicador__play,
  .explicador__dur { forced-color-adjust: none; }
  .explicador__capitulo[aria-current="true"] { border: 4px double ButtonText; }
  .explicador-modal__caja { border: 2px solid CanvasText; }
  .explicador-modal__cerrar { border-color: ButtonText; }
  /* El triángulo de «Créditos del video» es un borde: sin esto los bordes transparentes se pintan y
     queda un cuadrado. */
  .explicador__creditos summary::before {
    forced-color-adjust: none;
    border-left-color: ButtonText;
    border-block-color: transparent;
  }
}
@media print {
  .explicador__play, .explicador__dur, .explicador__error, .explicador-modal { display: none !important; }
}
