/*
 * site.css — shell compartido de Website V2.
 *
 * Consume tokens.css. No declara ningun valor visual propio: cada color,
 * espacio, tamano y radio sale del token correspondiente.
 *
 * Direccion: Expediente + Trazo + Producto Real. Editorial, asimetrico,
 * con aire y filetes. Nada de cards flotantes, glass, sombras de color,
 * radios grandes ni gradientes decorativos.
 *
 * Alcance: cabecera, navegacion, pie, contenedores, primitivas de shell.
 * El Home, el Trazo, el motion y la evidencia son fases posteriores.
 */

/* ================================================================== *
 * 1. Contenedores
 * ================================================================== */

.u-text,
.u-content,
.u-wide {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--grid-margin);
}

.u-text { max-width: var(--w-text); }
.u-content { max-width: var(--w-content); }
.u-wide { max-width: var(--w-wide); }

/* Medida de linea editorial: 65-75 caracteres. */
.u-measure { max-width: var(--measure); }

/* ================================================================== *
 * 2. Secciones
 * Ritmo variable, no un padding uniforme para todo.
 * ================================================================== */

.section {
  padding-block: var(--space-24);
}

@media (min-width: 1024px) {
  .section {
    padding-block: var(--space-32);
  }
}

.section--tight {
  padding-block: var(--space-12);
}

/* ================================================================== *
 * 3. Accesibilidad
 * ================================================================== */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/*
 * Anillo de foco general.
 * Canonizado en Sistema Visual V2, seccion 15: 2 px con desplazamiento
 * de 2 px, sobre el token --focus ya verificado por contraste.
 * Nunca se suprime sin sustituto y nunca se anima.
 */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Skip link: fuera del flujo hasta recibir foco. Sin JavaScript. */
.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 10;
  transform: translateY(-200%);
  display: inline-block;
  padding: var(--space-3) var(--space-4);
  background-color: var(--surface-raised);
  color: var(--ink-primary);
  border: var(--stroke-rule) solid var(--rule);
  border-radius: var(--radius-control);
  font-size: var(--size-small);
  text-decoration: none;
}

.skip-link:focus {
  transform: translateY(0);
}

/* ================================================================== *
 * 4. Enlaces
 * Los enlaces de texto NO son cian: tinta con subrayado de acento.
 * ================================================================== */

a {
  color: var(--ink-primary);
  text-decoration: underline;
  text-decoration-color: var(--accent-action);
  text-underline-offset: 0.18em;
}

a:hover {
  text-decoration-color: var(--accent-action-hover);
  text-decoration-thickness: 2px;
}

/* ================================================================== *
 * 5. Lockup de marca y crossfade
 *
 * Los dos SVG oficiales se superponen y se cruzan por opacidad. Ninguno
 * se recolorea, se edita ni se convierte en inline: son assets
 * referenciados y cacheables.
 *
 * El estado depende del atributo data-surface del contenedor, no de un
 * umbral de scroll inventado.
 * ================================================================== */

.logo {
  position: relative;
  display: block;
  width: clamp(156px, 14vw, 198px);
  aspect-ratio: 1867 / 346;
}

.logo__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: auto;
  transition: opacity var(--duration-base) var(--ease-ui);
}

[data-surface="light"] .logo__img--color { opacity: 1; }
[data-surface="light"] .logo__img--blanco { opacity: 0; }
[data-surface="inverse"] .logo__img--color { opacity: 0; }
[data-surface="inverse"] .logo__img--blanco { opacity: 1; }

/* ================================================================== *
 * 6. Cabecera
 * No es sticky: el canon no lo exige.
 * ================================================================== */

.header {
  border-bottom: var(--stroke-rule) solid var(--rule-soft);
  background-color: var(--surface-base);
}

.header[data-surface="inverse"] {
  background-color: var(--surface-inverse);
  border-bottom-color: var(--rule-on-inverse);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding-block: var(--space-6);
}

.header__home {
  display: block;
  text-decoration: none;
  border-radius: var(--radius-control);
}

/* ================================================================== *
 * 7. Navegacion
 * ================================================================== */

.nav__list {
  display: flex;
  align-items: baseline;
  gap: var(--space-8);
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * Enlaces de navegacion: sin caja, sin fondo, sin pastilla. El peso lo
 * dan la tinta y el filete inferior, que es la misma gramatica del resto
 * del sistema editorial.
 */
.nav__link {
  display: inline-block;
  padding-block: var(--space-2);
  color: var(--ink-secondary);
  font-size: var(--size-small);
  line-height: var(--lh-small);
  text-decoration: none;
  /* Filete estructural de 1px, como el resto del sistema. Los 2px del
     anillo de foco son otra cosa y no crean un grosor de navegacion. */
  border-bottom: var(--stroke-rule) solid transparent;
  transition: color var(--duration-fast) var(--ease-ui);
}

.nav__link:hover {
  color: var(--ink-primary);
  border-bottom-color: var(--rule);
}

/*
 * Ruta actual: tres senales a la vez —tinta plena, peso y filete de
 * acento—, para no depender del color.
 */
.nav__link--current {
  color: var(--ink-primary);
  font-weight: var(--weight-semibold);
  border-bottom-color: var(--accent-action);
}

.header[data-surface="inverse"] .nav__link {
  color: var(--ink-secondary-on-inverse);
}

.header[data-surface="inverse"] .nav__link:hover,
.header[data-surface="inverse"] .nav__link--current {
  color: var(--ink-primary-on-inverse);
}

/* ================================================================== *
 * 8. Control de navegacion movil
 * Oculto en desktop: la navegacion completa esta visible.
 * ================================================================== */

.nav-toggle {
  display: none;
  align-items: center;
  gap: var(--space-2);
  /* Area tactil de 44px sin que la caja pese como la del logo: el alto
     lo da el padding y el borde es un filete, no un contorno de boton. */
  min-height: 44px;
  padding: 0 var(--space-2);
  background-color: transparent;
  color: var(--ink-secondary);
  border: 0;
  border-bottom: var(--stroke-rule) solid var(--rule);
  border-radius: 0;
  font-family: var(--font-body);
  font-size: var(--size-small);
  letter-spacing: var(--tracking-caption);
  cursor: pointer;
}

.nav-toggle:hover {
  color: var(--ink-primary);
  border-bottom-color: var(--accent-action);
}

.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 16px;
  height: var(--stroke-rule);
  background-color: currentColor;
}

.nav-toggle__bars {
  position: relative;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.nav-toggle__bars::before { top: -5px; }
.nav-toggle__bars::after { top: 5px; }

/* ================================================================== *
 * 9. Shell movil
 * El umbral coincide con el breakpoint canonico de 768: por debajo, la
 * navegacion pasa a panel. El numero se repite aqui porque las custom
 * properties no funcionan como condicion de media query.
 * ================================================================== */

@media (max-width: 767px) {
  .nav-toggle {
    display: inline-flex;
  }

  /*
   * El panel no es un drawer de aplicacion ni una tabla de ajustes: es
   * la misma lista, respirando. Sin overlay, sin pantalla completa, sin
   * filete entre cada item.
   */
  .nav {
    display: none;
    width: 100%;
    order: 3;
    padding-block: var(--space-8) var(--space-4);
  }

  .nav[data-open="true"] {
    display: block;
  }

  .nav__list {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-6);
  }

  /*
   * La navegacion es UI, no titulacion: Public Sans, nunca Newsreader.
   * La jerarquia movil se gana con tamano, peso y aire dentro de la
   * escala de interfaz, no cambiando de familia.
   */
  .nav__link {
    display: inline-block;
    /* Area tactil comoda sin convertir el item en una fila de tabla. */
    min-height: 44px;
    padding-block: var(--space-2);
    font-size: var(--size-body-large);
    line-height: var(--lh-body-large);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-body);
    color: var(--ink-primary);
    border-bottom: var(--stroke-rule) solid transparent;
  }

  .nav__link--current {
    border-bottom-color: var(--accent-action);
  }

  .header__inner {
    flex-wrap: wrap;
    padding-block: var(--space-4);
  }

  /* Un solo filete separa la navegacion del contenido, no cinco. */
  .header[data-surface="light"] .nav[data-open="true"] {
    border-top: var(--stroke-rule) solid var(--rule-soft);
    margin-top: var(--space-4);
  }

  .header[data-surface="inverse"] .nav[data-open="true"] {
    border-top: var(--stroke-rule) solid var(--rule-on-inverse);
    margin-top: var(--space-4);
  }
}

/* ================================================================== *
 * 10. Pie — superficie inverse
 * Marca y estado arriba, enlaces debajo. Editorial, no un sitemap
 * tabulado: el bloque de marca manda y los grupos acompanan.
 * ================================================================== */

.footer {
  background-color: var(--surface-inverse);
  color: var(--ink-primary-on-inverse);
}

.footer__inner {
  padding-block: var(--space-24) var(--space-16);
}

.footer__lead {
  display: grid;
  gap: var(--space-6);
  padding-bottom: var(--space-16);
  border-bottom: var(--stroke-rule) solid var(--rule-on-inverse);
}

@media (min-width: 1024px) {
  .footer__lead {
    /* Asimetria deliberada: la marca no ocupa media pagina. */
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: var(--space-16);
    align-items: start;
  }
}

.footer__logo {
  display: block;
  width: clamp(176px, 17vw, 232px);
  height: auto;
}

.footer__status {
  margin: 0;
  max-width: var(--measure);
  color: var(--ink-secondary-on-inverse);
  font-size: var(--size-body);
  line-height: var(--lh-body);
}

.footer__status strong {
  color: var(--ink-primary-on-inverse);
  font-weight: var(--weight-semibold);
}

.footer__cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-12);
  padding-top: var(--space-16);
}

@media (min-width: 768px) {
  .footer__cols {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-12) var(--space-8);
  }
}

.footer__title {
  margin: 0 0 var(--space-6);
  font-family: var(--font-body);
  font-size: var(--size-state-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-state-label);
  text-transform: uppercase;
  color: var(--ink-muted-on-inverse);
}

.footer__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-4);
}

.footer__link {
  color: var(--ink-secondary-on-inverse);
  font-size: var(--size-small);
  line-height: var(--lh-small);
  text-decoration: none;
  border-bottom: var(--stroke-rule) solid transparent;
  transition: color var(--duration-fast) var(--ease-ui);
}

.footer__link:hover {
  color: var(--ink-primary-on-inverse);
  border-bottom-color: var(--accent-action-on-inverse);
}

/* ================================================================== *
 * 11. Andamio
 * Provisional. Desaparece cuando cada pagina reciba su contenido real.
 * ================================================================== */

.scaffold-note {
  max-width: var(--w-text);
  padding: var(--space-4);
  border-left: 2px solid var(--state-future);
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

[data-slot-pending] {
  color: var(--ink-muted);
  font-size: var(--size-small);
}

/* ================================================================== *
 * 12. Movimiento reducido
 * El crossfade desaparece; el logo correcto se muestra directamente.
 * El anillo de foco nunca se anima, ni con motion activo.
 * ================================================================== */

@media (prefers-reduced-motion: reduce) {
  .logo__img {
    transition: none;
  }
}

/* ================================================================== *
 * 13. Patterns de evidencia
 * Expediente: tipografia y unidades contables. Sin graficos, sin
 * badges, sin barras de progreso, sin estetica de dashboard.
 * ================================================================== */

/* --- statusLabel: geometria + tratamiento + texto, nunca solo color --- */

.status {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--size-state-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-state-label);
  text-transform: uppercase;
}

.status__mark {
  flex: none;
  width: var(--size-trace-node);
  height: var(--size-trace-node);
  align-self: center;
}

/* Disponible: circulo lleno. */
.status--available { color: var(--state-available); }
.status--available .status__mark {
  border-radius: 50%;
  background-color: currentColor;
}

/* En desarrollo: rombo hueco. Geometria distinta, no solo otro color. */
.status--in-progress { color: var(--state-progress); }
.status--in-progress .status__mark {
  transform: rotate(45deg);
  border: var(--stroke-rule) solid currentColor;
}

/* Proximo: cuadrado discontinuo. */
.status--future { color: var(--state-future); }
.status--future .status__mark {
  border: var(--stroke-rule) dashed currentColor;
}

.status__note {
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-caption);
  text-transform: none;
  color: var(--ink-muted);
}

[data-surface="inverse"] .status--available { color: var(--state-available-on-inverse); }
[data-surface="inverse"] .status--in-progress { color: var(--state-progress-on-inverse); }
[data-surface="inverse"] .status--future { color: var(--state-future-on-inverse); }

/* --- evidenceFigure: la cifra es tipografia --- */

.figures {
  display: grid;
  gap: var(--space-12);
  margin-top: var(--space-12);
}

@media (min-width: 768px) {
  .figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .figures--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .figures { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.figure {
  margin: 0;
  padding-top: var(--space-4);
  border-top: var(--stroke-rule) solid var(--rule);
}

.figure__value {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--size-data-large);
  line-height: var(--lh-data-large);
  letter-spacing: var(--tracking-data-large);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* El porcentaje acompana; nunca sustituye a la cifra absoluta. */
.figure__pct {
  font-family: var(--font-body);
  font-size: var(--size-body-large);
  font-weight: var(--weight-regular);
  color: var(--ink-muted);
}

.figure__units {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
}

.unit {
  width: var(--size-data-unit);
  height: var(--size-data-unit);
  border-radius: 50%;
  border: var(--stroke-rule) solid var(--rule);
}

.unit--on {
  background-color: var(--accent-action);
  border-color: var(--accent-action);
}

.figure__label {
  margin-top: var(--space-4);
  color: var(--ink-secondary);
  font-size: var(--size-small);
  line-height: var(--lh-small);
}

.figure__base {
  margin: var(--space-2) 0 0;
  color: var(--ink-muted);
  font-size: var(--size-caption);
}

/* --- screenshotFrame --- */

.frame {
  margin: var(--space-12) 0 0;
}

/* La figura puede desbordar la columna de medida para respirar, pero
   nunca el contenedor. Variante A permite desbordar; no permite deformar. */
.frame picture {
  display: block;
}

.frame__img {
  display: block;
  width: 100%;
  height: auto;
  border: var(--stroke-rule) solid var(--rule);
  border-radius: var(--radius-figure);
}

/* Pie numerado, Variante A. El numero es TEXTO del documento, no un
   contador de CSS: asi se lee sin hojas de estilo, entra en el DOM que
   la QA interroga, y un duplicado revienta en build en vez de pintarse
   tan tranquilo. */
.frame__num {
  color: var(--ink-muted);
}

.frame__caption {
  margin-top: var(--space-4);
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

.frame__claim {
  margin: var(--space-2) 0 0;
  color: var(--ink-muted);
  font-size: var(--size-small);
}

/* El aviso de demostracion es visible y pesa. Nunca letra pequena. */
.frame__demo {
  margin: var(--space-4) 0 0;
  padding: var(--space-4);
  border-left: var(--stroke-rule) solid var(--state-progress);
  color: var(--ink-primary);
  font-size: var(--size-small);
  line-height: var(--lh-small);
}

/* --- limitationBlock: mismo peso que los hallazgos --- */

.limits {
  padding-top: var(--space-8);
  border-top: var(--stroke-rule) solid var(--rule);
}

.limits__title {
  margin: 0 0 var(--space-6);
  font-family: var(--font-display);
  font-size: var(--size-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--tracking-h2);
  font-weight: var(--weight-semibold);
}

.limits__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-4);
  max-width: var(--measure);
}

.limits__list li {
  padding-left: var(--space-6);
  position: relative;
  color: var(--ink-primary);
  font-size: var(--size-body);
  line-height: var(--lh-body);
}

.limits__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: var(--space-3);
  height: var(--stroke-rule);
  background-color: var(--state-future);
}

/* ================================================================== *
 * 14. Home
 * Editorial y asimetrico. El hero es texto: sin video, sin mockup, sin
 * dashboard decorativo, y en movil nunca un recurso visual antes del
 * mensaje.
 * ================================================================== */

.hero {
  position: relative;
  background-color: var(--surface-inverse);
  color: var(--ink-primary-on-inverse);
  overflow: clip;
}

.hero__inner {
  position: relative;
  z-index: 1;
  padding-block: var(--space-24) var(--space-32);
}

@media (min-width: 1024px) {
  .hero__inner {
    /* Composicion asimetrica: el texto no ocupa el ancho completo. */
    padding-right: 22%;
  }
}

.hero__eyebrow {
  margin: 0 0 var(--space-8);
  color: var(--accent-action-on-inverse);
  font-size: var(--size-state-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-state-label);
  text-transform: uppercase;
}

.hero__title {
  margin: 0;
  max-width: 18ch;
  font-family: var(--font-display);
  font-size: var(--size-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--weight-semibold);
  font-optical-sizing: auto;
}

@media (min-width: 768px) {
  .hero__title { max-width: 22ch; }
}

.hero__lead {
  margin: var(--space-8) 0 0;
  max-width: var(--measure);
  color: var(--ink-secondary-on-inverse);
  font-size: var(--size-body-large);
  line-height: var(--lh-body-large);
}

.hero__actions {
  margin: var(--space-12) 0 0;
}

.link-quiet {
  color: var(--ink-primary-on-inverse);
  font-size: var(--size-small);
  text-decoration: none;
  border-bottom: var(--stroke-rule) solid var(--accent-action-on-inverse);
  padding-bottom: var(--space-1);
}

/*
 * Espacio reservado para los rails del Trazo. La fase de motion los
 * dibujara aqui; hoy solo ocupa su lugar en la composicion.
 */
.hero__rails {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/*
 * Transicion inverse hacia claro. Gradiente ESTATICO: el fondo no se
 * anima durante el scroll, por decision canonica.
 */
.surface-bridge {
  /* Banda propia de transicion, segun canon. Ademas del gradiente, es el
     espacio donde el bridge tiene sitio para quebrar y apuntar. */
  height: 34vh;
  min-height: 200px;
  background-image: linear-gradient(
    to bottom,
    var(--surface-inverse),
    var(--surface-base)
  );
}

.lead {
  font-size: var(--size-body-large);
  line-height: var(--lh-body-large);
  color: var(--ink-secondary);
}

.definition p {
  margin: 0 0 var(--space-4);
  font-family: var(--font-display);
  font-size: var(--size-h3);
  line-height: var(--lh-h3);
}

.definition p:last-child { margin-bottom: 0; }

.problem {
  display: grid;
  gap: var(--space-12);
  margin-top: var(--space-12);
}

@media (min-width: 768px) {
  .problem { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Sin cards: filete superior y aire. */
.problem__item {
  padding-top: var(--space-4);
  border-top: var(--stroke-rule) solid var(--rule);
}

.problem__item h3 {
  margin: 0 0 var(--space-3);
  font-size: var(--size-h3);
  line-height: var(--lh-h3);
}

.problem__item p {
  margin: 0;
  color: var(--ink-secondary);
  font-size: var(--size-body);
}

/* --- Flujo de ocho tramos --- */

.flow {
  margin: var(--space-12) 0 0;
  padding: 0;
  list-style: none;
}

.flow__step {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: var(--space-4);
  padding-block: var(--space-4);
  border-top: var(--stroke-rule) solid var(--rule-soft);
}

@media (min-width: 768px) {
  .flow__step {
    grid-template-columns: auto minmax(0, 22ch) 1fr;
    gap: var(--space-6);
  }
}

.flow__n {
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
  font-size: var(--size-small);
}

.flow__name {
  font-family: var(--font-display);
  font-size: var(--size-h3);
  line-height: var(--lh-h3);
}

/* --- Dos lados: ambos visibles a la vez, tambien en movil --- */

.sides {
  display: grid;
  gap: var(--space-8);
  margin-top: var(--space-12);
}

@media (min-width: 768px) {
  .sides {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-16);
  }
}

.sides__actor {
  padding-top: var(--space-4);
  border-top: var(--stroke-rule) solid var(--accent-action);
}

.sides__actor h3 {
  margin: 0 0 var(--space-3);
  font-size: var(--size-h3);
  line-height: var(--lh-h3);
}

.sides__actor p {
  margin: 0;
  color: var(--ink-secondary);
}

.sides__converge {
  margin-top: var(--space-8);
  color: var(--ink-secondary);
}

/* --- Leyenda de estados --- */

.legend {
  display: grid;
  gap: var(--space-4);
  margin: var(--space-8) 0 0;
  max-width: var(--measure);
}

@media (min-width: 768px) {
  .legend {
    grid-template-columns: auto 1fr;
    column-gap: var(--space-8);
    align-items: baseline;
  }
}

.legend dt { margin: 0; }

.legend dd {
  margin: 0;
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

/* --- Video comercial (seccion 9 del Home, condicional) ---
 *
 * Solo se emite cuando hay un asset aprobado en site.commercialVideo.
 * Ya no hay reservas de media con borde discontinuo: no queda ningun
 * hueco anunciado en el sitio, asi que tampoco su estilo.
 *
 * La proporcion la fijan los atributos width/height del elemento, que
 * salen de la configuracion. aspect-ratio aqui solo la sostiene cuando
 * el ancho disponible es menor que el intrinseco. */

.video {
  display: block;
  margin: var(--space-12) 0 0;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-figure);
  background-color: var(--surface-soft);
}

.video__transcript {
  margin-top: var(--space-4);
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

/* ================================================================== *
 * 15. Resultados de la validacion
 * ================================================================== */

.sample {
  margin-top: var(--space-4);
  font-size: var(--size-body-large);
  font-variant-numeric: tabular-nums;
}

.note {
  color: var(--ink-muted);
  font-size: var(--size-small);
  line-height: var(--lh-small);
}

/* Interpretacion: subordinada visualmente, no escondida. */
.h-sub {
  font-family: var(--font-body);
  font-size: var(--size-state-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-state-label);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.subordinate {
  color: var(--ink-secondary);
  font-size: var(--size-small);
  line-height: var(--lh-small);
}

.signals {
  margin: var(--space-8) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  max-width: var(--w-text);
}

.signal {
  display: grid;
  grid-template-columns: 7ch 1fr;
  gap: var(--space-4);
  align-items: baseline;
  padding-block: var(--space-3);
  border-top: var(--stroke-rule) solid var(--rule-soft);
}

.signal__count {
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-semibold);
}

.signal__label {
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

/* Advertencia sobre las senales de pago: adyacente y con peso. */
.caution {
  margin-top: var(--space-12);
  padding: var(--space-6);
  border-left: 2px solid var(--state-progress);
  background-color: var(--surface-soft);
}

.caution p { margin: 0 0 var(--space-3); }
.caution p:last-child { margin-bottom: 0; }

.plain {
  margin: var(--space-8) 0 0;
  padding-left: var(--space-6);
  display: grid;
  gap: var(--space-4);
}

.hypotheses li { color: var(--ink-secondary); }

.relations {
  display: grid;
  gap: var(--space-8);
  margin-top: var(--space-12);
  max-width: var(--w-text);
}

.relation {
  padding-top: var(--space-4);
  border-top: var(--stroke-rule) solid var(--rule-soft);
}

.relation__before {
  margin: 0 0 var(--space-2);
  color: var(--ink-muted);
  font-size: var(--size-small);
}

.relation__after {
  margin: 0;
  color: var(--ink-primary);
}

/* ================================================================== *
 * MOTION — estados finales por defecto
 *
 * Nada de lo que hay aqui esconde contenido. El estado por defecto de
 * cada narrativa es el FINAL: trazos completos, nodos visibles,
 * etiquetas presentes. El JavaScript solo esconde para volver a mostrar,
 * y unicamente despues de confirmar que puede animar.
 *
 * Sin JavaScript, con un error de carga o bajo movimiento reducido, esto
 * es lo que se ve, y esta terminado.
 *
 * Canon: Sistema Visual V2 secciones 9 a 13 y 20.
 * ================================================================== */

/* --- Rails del hero ------------------------------------------------ */

.hero-rail {
  position: absolute;
  top: 0;
  width: 1px;
  height: 48vh;
  transform-origin: top;
  /* Maximo 62% de opacidad. El cian no invade la superficie. */
  background-image: linear-gradient(
    to bottom,
    transparent,
    rgb(18 199 236 / 0.12) 18%,
    rgb(18 199 236 / 0.62) 72%,
    transparent
  );
}

/*
 * Uno solo en movil. La decision es del CSS, no del JavaScript: asi el
 * numero de rails es correcto tambien sin scripts.
 */
.hero-rail--c2,
.hero-rail--c10 {
  display: none;
}

.hero-rail--c6 {
  left: 50%;
}

@media (min-width: 901px) {
  .hero-rail--c2,
  .hero-rail--c10 {
    display: block;
  }

  /* Columnas 2, 6 y 10 de doce. */
  .hero-rail--c2 { left: 16.6667%; }
  .hero-rail--c10 { left: 83.3333%; }
}

/* --- Bridge: del rail central al Trazo ----------------------------- */

.surface-bridge {
  position: relative;
}

/*
 * El bridge ocupa el ancho del contenido, no una tira de 24 px. Necesita
 * ese ancho para que el quiebre hacia la izquierda exista de verdad: el
 * origen sigue en la columna del rail central, dentro del viewBox.
 */
.bridge {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.bridge__path {
  fill: none;
  stroke: var(--state-available-on-inverse);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: 0.62;
}

/* --- Trazo del flujo ----------------------------------------------- */

/*
 * El Trazo es la ESPINA de la seccion, no un grafico al pie.
 *
 * Antes iba detras de la lista y muy separado, y se leia como "una tabla
 * y ademas un diagrama pequeno". Ahora abre el bloque, ocupa una banda
 * ancha deliberada y la lista queda inmediatamente debajo, funcionando
 * como su leyenda. El hueco muerto entre ambos desaparece.
 */
.trace {
  margin-top: var(--space-8);
  margin-bottom: 0;
}

.trace__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.trace__path {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: miter;
  stroke-linecap: butt;
}

/* Disponible: solido, 2 px. */
.trace__path--available {
  stroke: var(--state-available);
  stroke-width: 2;
}

/* En desarrollo: discontinuo 6 4. Nunca recibe animacion de dibujo. */
.trace__path--progress {
  stroke: var(--state-progress);
  stroke-width: 2;
  stroke-dasharray: 6 4;
}

.trace__node--available {
  fill: var(--state-available);
}

/* Rombo abierto: el contorno es el segundo portador del estado. */
.trace__node--progress {
  fill: none;
  stroke: var(--state-progress);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}

/* Ordinal bajo cada vertice. Empareja el nodo con su fila de la lista. */
.trace__n {
  font-family: var(--font-ui);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  fill: var(--ink-muted);
}

/* La lista arranca pegada al Trazo: es su leyenda, no otro bloque. */
.trace + .flow {
  margin-top: var(--space-4);
}

/* --- Dos actores --------------------------------------------------- */

.actors {
  margin-top: var(--space-12);
}

.actors__steps {
  margin: 0;
  padding: 0;
  list-style: none;
}

.actors__step {
  max-width: var(--measure);
  padding-block: var(--space-8);
}

/*
 * Las tres etapas tienen que leerse como beats distintos ANTES de leer
 * cada frase. Lo hacen con composicion, no con efectos: un ordinal y un
 * filete que crece de una etapa a la siguiente, en paralelo al avance de
 * los carriles.
 */
.actors__step::before {
  content: counter(actor-step);
  display: block;
  margin-bottom: var(--space-2);
  font-family: var(--font-ui);
  font-variant-numeric: tabular-nums;
  font-size: var(--size-small);
  color: var(--ink-muted);
  border-top: var(--stroke-rule) solid var(--state-available);
  padding-top: var(--space-2);
  width: 3ch;
}

.actors__steps {
  counter-reset: actor-step;
}

.actors__step {
  counter-increment: actor-step;
}

.actors__step[data-step="2"]::before { width: 7ch; }
.actors__step[data-step="3"]::before { width: 11ch; }

/* La tercera etapa habla del limite: su filete cambia de estado. */
.actors__step[data-step="3"]::before {
  border-top-color: var(--state-progress);
}

.actors__step h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--size-h3);
}

.actors__step p {
  margin: 0;
  color: var(--ink-secondary);
}

.actors__stage {
  position: relative;
  margin-top: var(--space-8);
}

.actors__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.actors__lane {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: miter;
  stroke-linecap: butt;
}

.actors__lane--available {
  stroke: var(--state-available);
  stroke-width: 2;
}

/*
 * Tramo futuro. Visible desde el inicio, discontinuo y con menos
 * contraste. No se dibuja, no brilla y no recibe ningun tratamiento
 * equivalente al de una capacidad disponible.
 */
.actors__lane--progress {
  stroke: var(--state-progress);
  stroke-width: 2;
  stroke-dasharray: 6 4;
  opacity: 0.75;
}

.actors__node--available { fill: var(--state-available); }

.actors__node--progress {
  fill: none;
  stroke: var(--state-progress);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}

/*
 * Las etiquetas se anclan al PLOT, cuya caja es la del propio SVG.
 * Colgarlas del escenario las descolocaba: el escenario mide 100svh y el
 * dibujo apenas un tercio, asi que los porcentajes apuntaban a otro sitio.
 */
.actors__plot {
  position: relative;
  width: 100%;
}

.actors__tag {
  margin: 0;
  font-size: var(--size-small);
  color: var(--ink-secondary);
}

/*
 * Coordenadas derivadas del viewBox 800x260, para que la etiqueta caiga
 * junto a su nodo y no encima de la linea:
 *   Empresa (56,56) · Vendedor (56,204) · Oportunidad (392,130) · Venta (744,130)
 */
@media (min-width: 641px) {
  .actors__tag {
    position: absolute;
    white-space: nowrap;
  }

  .actors__tag--company { left: 1%;  top: 8.7%;  transform: translateY(-2.2em); }
  .actors__tag--seller  { left: 1%;  top: 91.3%; transform: translateY(1.2em); }
  .actors__tag--meeting { left: 43%; top: 50%;   transform: translateY(0.9em); }
  .actors__tag--pending { left: 96%; top: 50%;   transform: translate(-100%, 0.9em); }
}

@media (min-width: 901px) {
  /*
   * La escena pinned mide 260vh: tres etapas de 90svh mas margen.
   *
   * El reparto es asimetrico a proposito. El texto ocupa una columna
   * estrecha y el diagrama una banda ancha, para que 260vh de scroll
   * tengan algo que justificarlos: antes sobraba blanco por todas partes
   * y la escena pesaba menos de lo que el relato pedia.
   */
  /*
   * 270vh, y el numero dice la verdad.
   *
   * Antes declaraba 260vh, que nunca llegaba a aplicarse: tres etapas de
   * 90svh producen 270vh, la escena media 2430 px con viewport de 900, y
   * el min-height de 2340 quedaba por debajo del contenido. Era un
   * control muerto que invitaba a calibrar donde no se calibra nada.
   *
   * 270vh esta dentro del objetivo canonico 240-280vh, y coincide con lo
   * que la regla de tres etapas ya produce. Si alguien quiere acortar la
   * escena, lo que tiene que tocar es la altura de cada etapa.
   */
  .actors {
    position: relative;
    min-height: 270vh;
  }

  .actors__steps {
    width: 30%;
  }

  .actors__step {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 90svh;
  }

  .actors__stage {
    position: absolute;
    top: 0;
    /* Se desborda hacia el margen derecho a proposito: el canon permite
       que la media desborde la columna, y la escena necesita ese ancho
       para que 260vh de scroll esten justificados. */
    right: calc(var(--space-8) * -1);
    width: 66%;
    height: 100svh;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  .actors__tag {
    position: absolute;
  }

  .actors__tag--company { left: 0; top: 12%; }
  .actors__tag--seller { left: 0; bottom: 12%; }
  .actors__tag--meeting { left: 46%; top: 58%; }

  /*
   * `left` se anula a proposito. La regla de 641 px posiciona esta
   * etiqueta con `left: 96%` mas `translate(-100%, ...)`; aqui se cambia
   * a `right: 0`, y dejar el `left` puesto fijaba AMBOS bordes: la caja
   * se quedaba en el 4% sobrante, unos 22 px, y el texto se salia de la
   * pagina por la derecha. Con el desplazamiento horizontal ya no hace
   * falta, pero el vertical si: alinea con la etiqueta de Oportunidad.
   */
  .actors__tag--pending {
    left: auto;
    right: 0;
    top: 58%;
    transform: translateY(0.9em);
  }
}

/*
 * Movimiento reducido: no hay nada que desactivar, porque nada se
 * inicializa oculto. Se neutraliza la transicion por si algun estilo
 * heredado la introdujera.
 */
@media (prefers-reduced-motion: reduce) {
  .hero-rail,
  .trace__path,
  .trace__node--available,
  .actors__lane {
    transition: none;
  }
}

/* ================================================================== *
 * Paginas de segmento
 * ================================================================== */

/* --- El recorrido, en /como-funciona/ ------------------------------ *
 *
 * Dos zonas: el contenido a la izquierda, el Trazo a la derecha, quieto
 * con `position: sticky`.
 *
 * Sticky y NO pin. Un pin de ScrollTrigger secuestra el scroll y crea una
 * escena; sticky es CSS, no toca el scroll y la persona puede parar donde
 * quiera. La unica escena con pin del sitio sigue siendo la del Home.
 *
 * ── Sobre atenuar los tramos inactivos ──
 *
 * La direccion pedia bajar los inactivos a 0,55-0,65 de opacidad. Medido
 * sobre los tokens reales, eso rompe el suelo de contraste del canon:
 *
 *   ink-secondary sobre surface-base   1,00 -> 9,63:1
 *                                      0,80 -> 5,47:1
 *                                      0,65 -> 3,69:1   POR DEBAJO DE 4,5
 *                                      0,55 -> 2,89:1
 *   state-progress                     0,80 -> 3,45:1   POR DEBAJO DE 4,5
 *
 * Asi que la jerarquia se aplica al 0,80, que es lo mas bajo que aguanta
 * el minimo, y **la etiqueta de estado nunca se atenua**: el estado de un
 * tramo es justo lo que no puede perder legibilidad. La diferencia entre
 * activo e inactivo la llevan sobre todo la guia, el filete y el nodo,
 * que no son texto y pueden bajar todo lo que haga falta. */

.journey {
  margin-top: var(--space-8);
}

.journey__rail {
  margin: 0;
  padding: 0;
  /* Sin esto el <ol> pinta su marcador ademas del ordinal del tramo, y
     cada fila salia como "1. 1". */
  list-style: none;
}

.journey__stage {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  gap: var(--space-4);
  padding-block: var(--space-8);
  border-top: var(--stroke-rule) solid var(--rule-soft);
}

.journey__ord {
  margin: 0;
  padding-top: 0.2em;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-variant-numeric: tabular-nums;
  font-size: var(--size-small);
  color: var(--ink-muted);
}

/* --- Marcadores: CUATRO estados, y ninguno solo por color ---
 *
 * Rombo, como los nodos del Trazo: la marca es angular, nunca un circulo.
 * Relleno para disponible, hueco para futuro, y hueco CON nucleo para
 * mixto. La diferencia es de forma, asi que sobrevive en gris. */

.journey__mark {
  position: relative;
  width: 0.5rem;
  height: 0.5rem;
  flex: none;
  transform: rotate(45deg);
  transition: transform var(--duration-base) var(--ease-emphasis);
}

.journey__mark--available {
  background-color: var(--state-available);
}

.journey__mark--future {
  background-color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--state-progress);
}

/* Mixto: contorno ambar con corazon cian. Algo opera, la cadena no cierra. */
.journey__mark--mixed {
  background-color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--state-progress);
}

.journey__mark--mixed::after {
  content: "";
  position: absolute;
  inset: 30%;
  background-color: var(--state-available);
}

.journey__body > * + * {
  margin-top: var(--space-3);
}

.journey__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--size-h3);
  line-height: var(--lh-h3);
}

.journey__copy {
  margin: 0;
  max-width: var(--measure);
  color: var(--ink-secondary);
}

/* La captura entra despues de su explicacion: el mensaje va primero. */
.journey__body .frame {
  margin-top: var(--space-6);
}

/* --- Subestados de los tramos mixtos --- */

.submix {
  display: grid;
  gap: var(--space-2);
  padding-left: var(--space-4);
  border-left: var(--stroke-rule) solid var(--rule-soft);
}

.submix__row {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: var(--space-3);
  align-items: baseline;
}

.submix__text {
  margin: 0;
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

/* --- Jerarquia del tramo activo --- */

/*
 * Lo pone el runtime, no el CSS por defecto. Sin JavaScript no hay tramo
 * activo y los ocho se leen igual: correcto, porque el foco es una ayuda
 * de lectura, no informacion.
 *
 * La etiqueta de estado queda FUERA de la atenuacion, a proposito.
 */
.journey__name,
.journey__copy,
.submix__text,
.journey__body .frame picture {
  transition: opacity var(--duration-base) var(--ease-ui);
}

/*
 * Se atenua la IMAGEN de la figura, no la figura entera.
 *
 * Atenuar `.frame` arrastraba su pie y su claim, que van en ink-muted, y
 * a 0,8 caian a 3,52:1. Lo detecto la QA de contraste cuando empezo a
 * componer por opacidad efectiva. Una imagen no tiene suelo de contraste;
 * su pie si.
 */
[data-journey="on"] .journey__stage:not([aria-current="step"]) .journey__name,
[data-journey="on"] .journey__stage:not([aria-current="step"]) .journey__copy,
[data-journey="on"] .journey__stage:not([aria-current="step"]) .submix__text,
[data-journey="on"] .journey__stage:not([aria-current="step"]) .frame picture {
  opacity: 0.8;
}

.journey__stage[aria-current="step"] .journey__mark {
  transform: rotate(45deg) scale(1.5);
}

/*
 * El ordinal del tramo es informacion de navegacion, no tipografia de
 * lucimiento, y tiene que leerse SOLO: el 6 debe reconocerse sin mirar el
 * 5 ni el 7.
 *
 * Se comprobo en navegador que el DOM dice "6" y que la familia ya era
 * Public Sans con `tabular-nums`. El problema nunca fue el caracter.
 *
 * Primer intento: peso 500 y `--ink-secondary`. Subio el contraste de
 * 5,03:1 a 9,63:1 y aun asi una persona seguia leyendo un 3. Contraste no
 * es lo mismo que reconocimiento: a 14,5 px el bucle inferior del 6 se
 * cierra visualmente y la forma se vuelve ambigua. Lo que faltaba era
 * TAMANO y PESO, no color.
 *
 * Ahora: `--size-body`, que es el token canonico de 16-17 px, peso 600 y
 * tinta primaria. `lining-nums` fija cifras de altura uniforme —sin
 * descendentes que confundan la silueta— y `tabular-nums` mas un ancho
 * minimo mantienen los ocho ordinales alineados en la misma columna.
 *
 * Solo cambia el ordinal. Ni los titulos, ni los marcadores, ni
 * Newsreader en ningun otro sitio.
 */
.journey__num {
  font-family: var(--font-body);
  font-size: var(--size-body);
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink-primary);
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: "lnum" 1, "tnum" 1;
  min-inline-size: 1.2em;
}

/* Filete del tramo activo. Fino, del color de su estado. */
.journey__stage {
  border-left: 2px solid transparent;
  margin-left: -2px;
  padding-left: var(--space-4);
  transition: border-color var(--duration-base) var(--ease-ui);
}

.journey__stage[aria-current="step"] {
  border-left-color: var(--state-available);
}

.journey__stage[data-kind="future"][aria-current="step"],
.journey__stage[data-kind="mixed"][aria-current="step"] {
  border-left-color: var(--state-progress);
  border-left-style: dashed;
}

/* La figura del tramo activo marca su pertenencia con el borde, sin
   sombra, sin escala y sin flotar: sigue siendo evidencia. */
.journey__body .frame {
  transition: opacity var(--duration-base) var(--ease-ui),
              border-color var(--duration-base) var(--ease-ui);
}

/* --- El lienzo del Trazo --- */

.journey__canvas {
  position: sticky;
  align-self: start;
}

.journey__svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Nodos del Trazo. El activo crece; ninguno brilla. */
.journey__node,
.journey__core {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform var(--duration-base) var(--ease-emphasis),
              opacity var(--duration-base) var(--ease-ui);
}

.journey__node--available {
  fill: var(--state-available);
  opacity: 0.5;
  transform: scale(0.55);
}

.journey__node--future,
.journey__node--mixed {
  fill: none;
  stroke: var(--state-progress);
  stroke-width: 1.6;
  opacity: 0.6;
  transform: scale(0.7);
}

.journey__core {
  fill: var(--state-available);
  opacity: 0.75;
}

.journey__node[data-active="true"] {
  opacity: 1;
  transform: scale(1);
}

.journey__core[data-active="true"] {
  opacity: 1;
  transform: scale(1.15);
}

/* --- Guias hacia el contenido ---
 *
 * Es el puente fisico entre las dos columnas, y lo que impide que el
 * Trazo se pueda ignorar. Sale del nodo hacia la izquierda, hacia su
 * bloque de texto. Entra en 220 ms y sale en 160 ms: aparecer merece mas
 * tiempo que desaparecer. */

.journey__lead {
  stroke-width: 1.2;
  transform-box: fill-box;
  transform-origin: right center;
  transform: scaleX(0);
  transition: transform 160ms var(--ease-emphasis);
}

.journey__lead[data-active="true"] {
  transform: scaleX(1);
  transition-duration: var(--duration-base);
}

.journey__lead--available { stroke: var(--state-available); }

.journey__lead--future,
.journey__lead--mixed {
  stroke: var(--state-progress);
  stroke-dasharray: 4 3;
}

/*
 * Remate cian del extremo de contenido, solo en los mixtos.
 *
 * Entra con un retardo del ancho de la propia guia, para que aterrice
 * cuando la linea acaba de llegar y no antes: si apareciera a la vez,
 * seria un punto suelto esperando a que la linea lo alcance.
 */
.journey__terminal {
  fill: var(--state-available);
  opacity: 0;
  transition: opacity 120ms var(--ease-ui);
}

.journey__terminal[data-active="true"] {
  opacity: 1;
  transition: opacity 140ms var(--ease-ui) 200ms;
}

/* --- Rotulo del tramo activo --- */

.journey__label {
  margin: var(--space-4) 0 0;
  display: grid;
  gap: 2px;
  min-height: 2.6em;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 180ms var(--ease-ui), transform 180ms var(--ease-ui);
}

.journey__label[data-visible="true"] {
  opacity: 1;
  transform: none;
}

.journey__label-n {
  font-variant-numeric: tabular-nums;
  font-size: var(--size-small);
  color: var(--ink-muted);
  letter-spacing: 0.08em;
}

.journey__label-name {
  font-size: var(--size-small);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-secondary);
}

/* --- Revelado de la evidencia, una sola vez --- */

/*
 * El estado por defecto es el FINAL: la captura se ve entera. El runtime
 * solo marca `data-reveal="pending"` cuando ya sabe que puede animar, y
 * la quita al revelarla. Sin JavaScript nunca se pone, asi que nunca hay
 * nada recortado.
 */
/*
 * El revelado se aplica a la IMAGEN, no a la figura entera.
 *
 * Dos razones, y las dos las encontro la QA:
 *
 *   1. `opacity: 0.88` sobre la figura arrastraba su pie y su claim, en
 *      ink-muted, hasta 4,13:1. Es un estado que puede durar para
 *      siempre si nadie baja hasta ese tramo, asi que no es transitorio.
 *   2. Un `clip-path` sobre la figura recortaria tambien el texto del
 *      pie, que es contenido, no adorno.
 *
 * La imagen no tiene suelo de contraste; su pie si.
 */
.journey__body .frame[data-reveal="pending"] picture {
  clip-path: inset(0 8% 0 0);
  transform: translateY(12px);
  opacity: 0.88;
}

.journey__body .frame[data-reveal="done"] picture {
  clip-path: inset(0 0 0 0);
  transform: none;
  opacity: 1;
  transition: clip-path var(--duration-trace) var(--ease-emphasis),
              transform var(--duration-trace) var(--ease-emphasis),
              opacity var(--duration-trace) var(--ease-emphasis);
}

/* --- Desktop: dos zonas --- */

@media (min-width: 901px) {
  /*
   * 62 / 30 con su canal. La columna del Trazo se lleva solo lo que
   * necesita: darle media pagina dejaba un hueco enorme alrededor de una
   * linea fina, que es la version elegante de no componer nada.
   */
  .journey {
    display: grid;
    grid-template-columns: minmax(0, 62fr) minmax(0, 30fr);
    column-gap: var(--space-6);
    align-items: start;
  }

  .journey__rail { grid-column: 1; }

  .journey__canvas {
    grid-column: 2;
    top: 18vh;
  }

  .journey__svg { max-height: 66vh; }

  .journey__stage {
    grid-template-columns: 3rem minmax(0, 1fr);
  }
}

/* --- Movil: el recorrido lo dibujan los propios tramos --- */

@media (max-width: 900px) {
  /*
   * Sin lienzo aparte. Escalar un viewBox en una columna estrecha lo
   * achica tambien de alto, asi que quedaba un garabato; y ensanchar la
   * columna le robaba el ancho al texto, que a 375 px no sobra.
   *
   * El recorrido vertical lo dibujan los tramos: su rombo y la linea que
   * los une. Solida donde opera, discontinua donde no, con la ruptura
   * entre el quinto y el sexto. Misma semantica, cero bytes de SVG.
   */
  .journey__canvas { display: none; }

  .journey__stage {
    position: relative;
    grid-template-columns: 1.5rem minmax(0, 1fr);
    gap: var(--space-3);
    border-left: 0;
    margin-left: 0;
    padding-left: var(--space-1);
  }

  .journey__stage::before {
    content: "";
    position: absolute;
    left: 0.42rem;
    top: 0;
    bottom: 0;
    border-left: 2px solid var(--state-available);
  }

  .journey__stage[data-kind="future"]::before,
  .journey__stage[data-kind="mixed"]::before {
    border-left-style: dashed;
    border-left-color: var(--state-progress);
  }

  /* LA RUPTURA. El sexto tramo no arranca su linea pegada al quinto:
     empieza mas abajo, y ese hueco es el mensaje de la pagina. */
  .journey__stage[data-flow-stage="6"]::before { top: 14px; }

  /* El ultimo tramo no cuelga una linea hacia la nada. */
  .journey__stage:last-child::before { bottom: 50%; }

  /* El rombo va por delante de la linea, no atravesado por ella. */
  .journey__ord {
    position: relative;
    z-index: 1;
  }

  .journey__mark { box-shadow: 0 0 0 4px var(--surface-base); }

  .journey__mark--future,
  .journey__mark--mixed {
    box-shadow: 0 0 0 4px var(--surface-base), inset 0 0 0 1.5px var(--state-progress);
  }

  /* El filete del activo caeria sobre la linea del recorrido, asi que
     aqui el activo se marca solo con el rombo, que ya cambia de tamano. */
  .journey__stage[aria-current="step"] { border-left-color: transparent; }
}

/* ================================================================== *
 * 24. /poc/ — video y formulario de la validacion
 * ================================================================== */

/* --- El video ---
 *
 * `preload="none"` y poster: no se descargan 11,7 MB a quien solo venia a
 * leer. La proporcion se reserva con width/height, no con una caja
 * discontinua, asi que no hay salto de layout al cargar. */

.poc-video {
  display: block;
  margin: var(--space-6) 0 0;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-figure);
  background-color: var(--surface-soft);
}

/* --- La transcripcion ---
 *
 * Va debajo del video y desplegable, no escondida en otra pagina: un
 * subtitulo no le sirve a quien no puede reproducir el video. */

.poc-tr {
  margin-top: var(--space-4);
  border-top: var(--stroke-rule) solid var(--rule-soft);
  padding-top: var(--space-3);
}

.poc-tr > summary {
  cursor: pointer;
  font-size: var(--size-small);
  color: var(--ink-secondary);
}

.poc-tr__body {
  margin-top: var(--space-4);
  display: grid;
  gap: var(--space-2);
  max-width: var(--measure);
}

.poc-tr__line {
  margin: 0;
  color: var(--ink-secondary);
  font-size: var(--size-small);
}

.poc-tr__t {
  display: inline-block;
  min-inline-size: 5ch;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* --- El formulario --- */

.poc-form {
  margin-top: var(--space-6);
  display: grid;
  gap: var(--space-6);
  max-width: 46rem;
}

/* Progreso. Lo pone el runtime; sin JavaScript no aparece, y no aparecer
   es correcto: no habria nada que contar. */
.poc-progress {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-left: 2px solid var(--state-available);
  background-color: var(--surface-soft);
  font-size: var(--size-small);
  color: var(--ink-secondary);
  font-variant-numeric: tabular-nums;
}

.poc-field {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border: 0;
}

.poc-label {
  font-size: var(--size-small);
  font-weight: 500;
  color: var(--ink-primary);
  max-width: var(--measure);
}

.poc-req { color: var(--state-progress); }

.poc-input {
  font: inherit;
  font-size: var(--size-body);
  color: var(--ink-primary);
  background-color: var(--surface-raised);
  border: var(--stroke-rule) solid var(--rule);
  border-radius: var(--radius-control, 4px);
  padding: 0.7em 0.8em;
  width: 100%;
  /* El area tactil minima del canon vive en Sistema Visual seccion 15. */
  min-height: 44px;
}

.poc-input:focus-visible {
  outline: 2px solid var(--state-available);
  outline-offset: 2px;
}

.poc-textarea { min-height: 7em; resize: vertical; }
.poc-select { appearance: auto; }

/* --- Grupos de casillas --- */

.poc-boxes {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

@media (min-width: 641px) {
  .poc-boxes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.poc-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  /* 44 px de alto util, para que la casilla se pueda tocar con el dedo. */
  min-height: 44px;
  padding: var(--space-2) 0;
  font-size: var(--size-small);
  color: var(--ink-secondary);
  cursor: pointer;
}

.poc-check input {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.1em;
  accent-color: var(--state-available);
}

.poc-check input:focus-visible {
  outline: 2px solid var(--state-available);
  outline-offset: 2px;
}

/* --- Consentimiento y envio --- */

.poc-consent {
  margin: 0;
  font-size: var(--size-small);
  color: var(--ink-secondary);
}

.poc-submit {
  justify-self: start;
  font: inherit;
  font-size: var(--size-body);
  font-weight: 500;
  color: var(--ink-primary-on-inverse);
  background-color: var(--surface-inverse);
  border: 0;
  border-radius: var(--radius-control, 4px);
  padding: 0.8em 1.6em;
  min-height: 44px;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-ui);
}

.poc-submit:active { transform: scale(0.98); }

.poc-submit:focus-visible {
  outline: 2px solid var(--state-available);
  outline-offset: 3px;
}

.poc-submit[disabled] { opacity: 0.6; cursor: default; }

/* El estado lo anuncia `role="status"`. El color acompana, no informa
   solo: el mensaje siempre dice en palabras lo que ocurrio. */
.poc-status {
  margin: 0;
  min-height: 1.5em;
  font-size: var(--size-small);
  color: var(--ink-secondary);
}

.poc-status[data-state="error"] { color: var(--state-progress); }
.poc-status[data-state="sent"] { color: var(--state-available); }

@media (prefers-reduced-motion: reduce) {
  .poc-submit { transition: none; }
}
