/* ==========================================================================
   prototype-v2 — Sistema visual "Documento" (Dirección A)
   + gramática antes/antes→transformación→preparado dentro de las escenas (C)

   Construido desde cero. No reutiliza reglas de website/styles.css.
   Mobile-first: base ~390px, luego 48rem / 64rem / 90rem.
   ========================================================================== */

:root {
  color-scheme: light;

  /* Paleta provisional — el azul de acento NO está aprobado como definitivo */
  --bg: #ffffff;
  --ink: #101014;
  --ink-secondary: #5b5b66;
  /* Tinta de lectura: para párrafos largos con información importante dentro
     de los casos (resumen, El problema, Lo que hice, Imagina que…). Más
     oscura que --ink-secondary a propósito, para que ese texto se lea sin
     enfocar la vista, sin llegar al peso de los titulares en --ink. */
  --ink-reading: #3f4048;
  --line: #e6e6ea;
  --surface: #f5f5f7;
  --accent: #2440d9;
  --accent-contrast: #ffffff;

  /* Estados funcionales — solo dentro de escenas, con significado fijo */
  --state-ready: #15803d;
  --state-review: #b45309;
  --state-stop: #b91c1c;

  /* Tipografía: system stack robusto, sin webfont ni pesos no estándar.
     Cada plataforma recibe su fuente nativa (San Francisco / Segoe UI /
     Roboto); solo se usan pesos estándar 400/500/600/700/800, que no
     dependen de una familia variable específica y colapsan de forma
     previsible en cualquier fallback. Ver prototype-v2/README.md. */
  --font-sans:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";

  /* Layout */
  --content: 74rem;
  --reading: 42rem;
  --pad: clamp(1.25rem, 5vw, 4rem);
  --radius: 0.6rem;
  --radius-small: 0.35rem;

  /* Espaciado — escala de 8px consistente, sin valores ad-hoc */
  --space-1: 0.5rem;
  --space-2: 0.75rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2rem;
  --space-6: 3rem;
  --space-7: 4rem;
  --space-8: 6rem;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img,
svg {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

button {
  font: inherit;
  color: inherit;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

h1,
h2,
h3,
p,
figure {
  margin: 0;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Objetivos táctiles cómodos en todo el sitio */
button,
a {
  -webkit-tap-highlight-color: transparent;
}

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ==========================================================================
   Contenedores
   ========================================================================== */

.wrap {
  width: min(100%, var(--content));
  margin-inline: auto;
  padding-inline: var(--pad);
}

.measure {
  max-width: var(--reading);
}

/* ==========================================================================
   Skip link
   ========================================================================== */

.skip-link {
  position: fixed;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 100;
  background: var(--ink);
  color: var(--bg);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-small);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-6rem);
  transition: transform 0.18s ease;
}

.skip-link:focus {
  transform: translateY(0);
}

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 4rem;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  padding-block: var(--space-2);
}

.brand {
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
  text-decoration: none;
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.lang-switch {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.lang-switch a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  min-width: 2.75rem;
  padding-inline: 0.4rem;
  text-decoration: none;
  color: var(--ink-secondary);
  border-radius: var(--radius-small);
}

.lang-switch a[aria-current="true"] {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  text-decoration-thickness: 2px;
}

.lang-switch a:hover {
  color: var(--ink);
}

.lang-switch__sep {
  color: var(--line);
}

.header-contact {
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
}

.header-contact:hover {
  color: var(--accent);
}

/* ==========================================================================
   Hero
   Orden en el DOM (y por tanto en mobile): copy → foto → CTA.
   En desktop se reorganiza visualmente vía grid-template-areas, sin
   alterar el orden de lectura/foco.
   ========================================================================== */

.hero {
  padding-block: var(--space-7) var(--space-6);
  display: grid;
  gap: var(--space-5);
}

.hero > * {
  min-width: 0;
}

.hero__copy {
  display: grid;
  gap: var(--space-4);
}

.hero h1 {
  font-size: clamp(2.4rem, 10vw, 4.6rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  max-width: 16ch;
}

.hero__voice {
  font-size: clamp(1.15rem, 4.5vw, 1.5rem);
  font-weight: 500;
  color: var(--ink);
  max-width: 38ch;
  line-height: 1.4;
}

.hero__intro {
  font-size: clamp(1rem, 3.5vw, 1.1rem);
  color: var(--ink-secondary);
  max-width: 40ch;
  line-height: 1.55;
}

/* Slot de retrato: vertical en todos los tamaños (misma fotografía real
   futura). object-position ajustable vía --portrait-position cuando se
   añada la <img> real (ver comentario FUTURO en el HTML). */
.portrait-slot {
  --portrait-position: center;
  aspect-ratio: 4 / 5;
  width: 100%;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-secondary);
  position: relative;
  overflow: hidden;
}

.portrait-slot__picture {
  display: block;
  width: 100%;
  height: 100%;
}

.portrait-slot__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--portrait-position, center);
  display: block;
}

.portrait-slot__mark {
  width: 5.5rem;
  height: 5.5rem;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: 0.04em;
}

.hero__primary-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2.75rem;
  border: 0;
  border-bottom: 2px solid currentColor;
  background: none;
  padding-block: 0.2rem;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  width: fit-content;
}

@media (min-width: 48rem) {
  .hero {
    grid-template-columns: minmax(0, 1.15fr) minmax(16rem, 0.85fr);
    grid-template-areas:
      "copy  photo"
      "cta   photo";
    align-items: center;
    row-gap: var(--space-4);
  }

  .hero__copy {
    grid-area: copy;
  }

  .portrait-slot {
    grid-area: photo;
    width: min(100%, 22rem);
  }

  .hero__primary-link {
    grid-area: cta;
  }
}

/* ==========================================================================
   Problemas — único índice a los cuatro casos (sin eyebrow ni hint visibles;
   el nombre accesible vive en aria-label de la sección/nav)
   ========================================================================== */

.problems-nav {
  padding-block: var(--space-4);
}

/* ==========================================================================
   Case nav — único índice de los cuatro problemas
   2×2 en mobile (flex-wrap con items al 45%), fila a partir de 48rem.
   ========================================================================== */

.case-nav {
  display: flex;
  flex-wrap: wrap;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}

.case-nav__item {
  flex: 1 1 45%;
  text-align: center;
  padding-block: var(--space-3);
  text-decoration: none;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  min-height: 2.75rem;
}

.case-nav__item:nth-child(2n) {
  border-right: 0;
}

.case-nav__item:hover {
  background: var(--surface);
}

@media (min-width: 48rem) {
  .case-nav__item {
    flex: 1 1 auto;
    border-right: 1px solid var(--line);
    border-bottom: 0;
  }

  .case-nav__item:last-child {
    border-right: 0;
  }

  .case-nav__item:nth-child(2n) {
    border-right: 1px solid var(--line);
  }
}

/* ==========================================================================
   Cases — cuatro capítulos independientes
   .case es el full-bleed que alterna superficie; .case__inner es el
   contenido con ancho de lectura (.wrap).
   ========================================================================== */

.case {
  border-bottom: 1px solid var(--line);
}

.case[data-surface="b"] {
  background: var(--surface);
}

/* Ritmo del caso cerrado: padding generoso, no altura de viewport forzada.
   Se apoya en contenido + espaciado, tolera cualquier tamaño de fuente,
   idioma o zoom sin recortar ni desbordar. */
.case__inner {
  padding-block: var(--space-8);
}

.case__header {
  display: grid;
  gap: var(--space-5);
}

.case.is-open .case__inner {
  box-shadow: inset 3px 0 0 var(--accent);
}

.case__heading {
  display: grid;
  gap: var(--space-2);
}

.case__label {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-secondary);
}

.case.is-open .case__label {
  color: var(--accent);
}

.case__heading h2 {
  font-size: clamp(1.6rem, 6vw, 2.6rem);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.015em;
  max-width: 22ch;
}

.case__lead {
  display: grid;
  gap: var(--space-3);
  max-width: var(--reading);
}

.case__summary {
  font-size: clamp(1rem, 3.4vw, 1.1rem);
  color: var(--ink-reading);
  line-height: 1.6;
}

.expand-button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2.75rem;
  border: 0;
  border-bottom: 2px solid currentColor;
  background: none;
  cursor: pointer;
  padding-block: 0.2rem;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  width: fit-content;
}

.expand-button:hover {
  color: var(--accent);
}

.case__detail {
  margin-top: var(--space-6);
  display: grid;
  gap: var(--space-6);
}

.case__detail[hidden] {
  display: none;
}

.detail-grid {
  display: grid;
  gap: var(--space-5);
}

.detail-block {
  display: grid;
  gap: var(--space-2);
  padding-left: var(--space-3);
  border-left: 3px solid var(--line);
}

.detail-block--solution {
  border-left-color: var(--accent);
}

.detail-block h3 {
  font-size: 1rem;
  font-weight: 700;
}

.detail-block p {
  font-size: 1rem;
  color: var(--ink-reading);
  line-height: 1.6;
  max-width: var(--reading);
}

.imagine {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-4);
  display: grid;
  gap: var(--space-2);
}

.case[data-surface="b"] .imagine {
  background: var(--bg);
}

.imagine h3 {
  font-size: 1.05rem;
  font-weight: 700;
}

.imagine p {
  color: var(--ink-reading);
  line-height: 1.6;
  max-width: var(--reading);
}

/* --------------------------------------------------------------------------
   Escena: gramática ANTES → TRANSFORMACIÓN → APARTADO/REVISIÓN → PREPARADO
   Layout de flujo (grid/flex), sin coordenadas absolutas, para tolerar
   textos de largo variable en ES/EN/FR.
   -------------------------------------------------------------------------- */

.scene {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg);
}

.scene__heading {
  padding: var(--space-4) var(--space-4) 0;
  display: grid;
  gap: var(--space-1);
}

.scene__eyebrow {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-secondary);
}

.scene__heading h3 {
  font-size: clamp(1.15rem, 4vw, 1.5rem);
  font-weight: 700;
  line-height: 1.3;
  max-width: 32ch;
}

.scene__duration {
  font-size: 0.82rem;
  color: var(--ink-secondary);
}

.scene__stage-label {
  padding: var(--space-3) var(--space-4) 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink-secondary);
  min-height: 1.4em;
}

.scene__body {
  padding: var(--space-4);
  display: grid;
  gap: var(--space-3);
}

@media (min-width: 64rem) {
  .scene__body {
    grid-template-columns: 1fr auto 1fr;
    align-items: stretch;
    gap: var(--space-4);
  }
}

.scene__pane {
  background: var(--surface);
  border-radius: var(--radius-small);
  padding: var(--space-3);
  display: grid;
  gap: var(--space-2);
  align-content: start;
}

.scene__pane-title {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-secondary);
}

.scene__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 0.55rem 0.75rem;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  font-size: 0.9rem;
  opacity: 0.5;
  transform: translateY(0.4rem);
  transition: opacity 0.5s ease, transform 0.5s ease, border-color 0.4s ease,
    color 0.4s ease;
}

.scene[data-step="1"] .scene__item[data-appear="1"],
.scene[data-step="2"] .scene__item[data-appear="1"],
.scene[data-step="3"] .scene__item[data-appear="1"],
.scene[data-step="4"] .scene__item[data-appear="1"] {
  opacity: 1;
  transform: translateY(0);
}

.scene[data-step="2"] .scene__item[data-appear="2"],
.scene[data-step="3"] .scene__item[data-appear="2"],
.scene[data-step="4"] .scene__item[data-appear="2"] {
  opacity: 1;
  transform: translateY(0);
}

.scene[data-step="3"] .scene__item[data-appear="3"],
.scene[data-step="4"] .scene__item[data-appear="3"] {
  opacity: 1;
  transform: translateY(0);
}

.scene[data-step="4"] .scene__item[data-appear="4"] {
  opacity: 1;
  transform: translateY(0);
}

.scene__item[data-state="review"] {
  border-color: var(--state-review);
  color: var(--state-review);
  font-weight: 600;
}

.scene__item[data-state="ready"] {
  border-color: var(--state-ready);
  color: var(--state-ready);
  font-weight: 600;
}

.scene__item strong {
  font-weight: 700;
}

.scene__arrow {
  display: none;
}

@media (min-width: 64rem) {
  .scene__arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--line);
    font-size: 1.4rem;
  }
}

.scene__controls {
  display: flex;
  gap: var(--space-2);
  padding: 0 var(--space-4) var(--space-4);
}

.scene-progress {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 0.3rem;
  padding: 0 var(--space-4);
}

.scene-progress span {
  height: 0.22rem;
  border-radius: 999px;
  background: var(--line);
}

.scene-progress span.is-complete {
  background: var(--accent);
}

/* Línea de etapas interactiva (Facturas): los segmentos decorativos se
   sustituyen por botones reales con objetivo táctil propio. No afecta a
   Soportes/Pagos/Correos, que no llevan [data-progress-interactive]. */
.scene-progress[data-progress-interactive] {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  padding: var(--space-2) var(--space-4) 0;
}

/* Ancho fluido: ocho puntos de 2.25rem fijos necesitaban 310px y solo hay
   300px a 390px de ancho, así que envolvían a dos filas (y peor a 320px).
   Repartiendo el ancho disponible caben siempre en UNA fila —27,9px a
   320px— conservando 2.75rem de alto de objetivo táctil. */
.stage-dot {
  flex: 1 1 0;
  min-width: 1.5rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.stage-dot::before {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--line);
  transition: background 0.3s ease, transform 0.3s ease;
}

.stage-dot.is-complete::before {
  background: var(--accent);
}

.stage-dot.is-current::before {
  background: var(--accent);
  transform: scale(1.5);
}

.control-button {
  flex: 1 1 0;
  min-height: 2.75rem;
  border: 1px solid var(--ink);
  background: transparent;
  border-radius: var(--radius-small);
  font-weight: 700;
  font-size: 0.82rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

.control-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.text-alternative {
  border-top: 1px solid var(--line);
  padding: var(--space-3) var(--space-4);
}

.text-alternative summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 0.88rem;
  min-height: 2.75rem;
  display: flex;
  align-items: center;
}

.text-alternative ol {
  margin-top: var(--space-2);
  display: grid;
  gap: var(--space-1);
  padding-left: 1.2rem;
  list-style: decimal;
  color: var(--ink-secondary);
  font-size: 0.9rem;
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   Recorrido visual de Facturas — UN SOLO CANVAS ACOTADO.

   Principio recuperado de website/ V1.3 (.process-canvas): el recorrido
   entero ocurre dentro de un recuadro de ALTURA CONSTANTE con overflow
   hidden, y todo lo que hay dentro está en position:absolute — así el
   contenido nunca puede empujar la altura y el visitante nunca tiene que
   hacer scroll para seguir un objeto. De V1.3 se recupera el principio,
   NO la estética (ni su color, ni su tipografía, ni sus offsets en rem
   hardcodeados, que allí provocaban solapes reales en mobile).

   Tres regiones, no siete cajas. Dos son de doble uso y las vacías
   COLAPSAN A 0 para que la ventana ocupe el hueco:

     .iscene__rail   «Entradas» (et. 1-2) → 0 (et. 3-6) → «Etapa de
                     registro» (et. 7-8)
     .iscene__tool   la ventana de herramienta; su rótulo recorre
                     Validador → Preparación → Archivo de carga
     .iscene__band   0 (et. 1-3) → «No continúan» (et. 4+), con una
                     subsección «Revisión» extra durante la etapa 5

   La geometría se deriva de custom properties conmutadas por
   [data-rail]/[data-band] en el root, nunca de constantes por breakpoint.
   Los 5 nodos .iscene__card y el archivo existen UNA sola vez en el DOM y
   viajan entre slots; InvoiceScene (app.js) anima la diferencia con FLIP.

   Exclusivo de Facturas — Soportes/Pagos/Correos conservan .scene__body.
   -------------------------------------------------------------------------- */

.iscene {
  /* Ritmo interno — todo lo demás se calcula a partir de esto */
  --inset: 0.625rem;
  --region-gap: 0.5rem;
  --region-pad: 0.5rem;
  --card-h: 1.75rem;
  --card-gap: 0.375rem;
  --label-h: 1.28rem;
  --divider-h: 0.5625rem;
  --bar-h: 1.875rem;
  --move-dur: 0.58s;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* Alturas de región, derivadas del contenido que cada una debe alojar */
  /* El +2px absorbe el borde del divisor y el redondeo subpíxel de los
     rótulos: sin él la franja de la etapa 5 desbordaba 3px y el
     overflow:hidden recortaba su padding inferior. */
  --rail-size: calc(var(--label-h) + var(--card-h) + 2 * var(--region-pad) + 0.25rem);
  --band-stop: calc(2 * var(--region-pad) + var(--label-h) + 2 * var(--card-h) + var(--card-gap) + 2px);
  --band-review: calc(2 * var(--region-pad) + 2 * var(--label-h) + 3 * var(--card-h) + var(--card-gap) + var(--divider-h) + 4px);

  /* Conmutadas por etapa más abajo. 0 = región colapsada. */
  --rail-h: 0px;
  --rail-gap: 0px;
  --band-h: 0px;
  --band-gap: 0px;

  position: relative;
  height: clamp(16rem, 50vh, 28rem);
  overflow: hidden;
  margin: var(--space-3) var(--space-3) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/* Regiones vacías → 0. Solo se les da altura cuando tienen contenido. */
.iscene[data-rail="entradas"] {
  --rail-h: var(--rail-size);
  --rail-gap: var(--region-gap);
}

/* La franja de registro aloja el archivo con su confirmación, un objeto
   algo más ancho que una factura: unos px más de aire que el abanico. */
.iscene[data-rail="registro"] {
  --rail-h: calc(var(--rail-size) + 0.5rem);
  --rail-gap: var(--region-gap);
}

.iscene[data-band="stop"] {
  --band-h: var(--band-stop);
  --band-gap: var(--region-gap);
}

.iscene[data-band="review"] {
  --band-h: var(--band-review);
  --band-gap: var(--region-gap);
}

/* --- Regiones ------------------------------------------------------------ */

.iscene__rail,
.iscene__tool,
.iscene__band {
  position: absolute;
  left: var(--inset);
  right: var(--inset);
  /* Sin transición de geometría A PROPÓSITO: si las regiones animaran su
     tamaño, las tarjetas medirían un destino todavía en movimiento y el
     cálculo FLIP quedaría desfasado. Solo se animan las tarjetas. */
  transition: opacity 0.3s ease, background-color 0.35s ease,
    border-color 0.35s ease;
}

.iscene__rail {
  top: var(--inset);
  height: var(--rail-h);
  padding: var(--region-pad);
  border-radius: var(--radius-small);
  border: 1px dashed var(--line);
  overflow: hidden;
}

/* Colapsada de verdad: sin padding ni borde, si no conservaría 18px que
   le robarían altura a la ventana. visibility:hidden además la saca del
   árbol de accesibilidad y garantiza que su contenido no pinte. */
.iscene[data-rail="none"] .iscene__rail,
.iscene[data-band="none"] .iscene__band {
  opacity: 0;
  visibility: hidden;
  padding: 0;
  border-width: 0;
}

/* Etapa de registro: la misma franja, ahora sólida y en tinta — señal de
   que el espacio cambió de función, no de que volvimos al principio. */
.iscene[data-rail="registro"] .iscene__rail {
  border-style: solid;
  border-color: var(--ink);
  background: var(--ink);
}

.iscene[data-rail="registro"] .iscene__region-label {
  color: var(--bg);
  opacity: 0.72;
}

.iscene__tool {
  top: calc(var(--inset) + var(--rail-h) + var(--rail-gap));
  bottom: calc(var(--inset) + var(--band-h) + var(--band-gap));
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  overflow: hidden;
}

/* La ventana "encendida" mientras trabaja (calco funcional de V1.3) */
.iscene[data-tool] .iscene__tool {
  border-color: var(--accent);
}

.iscene[data-tool="idle"] .iscene__tool {
  border-color: var(--line);
}

/* Barra de título: SOLO el rótulo. Sin los tres puntos decorativos de
   V1.3 — son decoración de sistema operativo, no información. */
.iscene__tool-bar {
  flex: 0 0 auto;
  height: var(--bar-h);
  display: flex;
  align-items: center;
  padding-inline: var(--region-pad);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  margin: 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
}

.iscene__tool-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--region-pad);
  overflow: hidden;
}

.iscene__band {
  bottom: var(--inset);
  height: var(--band-h);
  padding: var(--region-pad);
  border-radius: var(--radius-small);
  border: 1px solid var(--line);
  background: var(--bg);
  overflow: hidden;
}


/* Dos subsecciones ROTULADAS POR SEPARADO: «Revisión» nunca cubre a las
   Facturas 4 y 5, y «No continúan» nunca cubre a la 3. La franja está
   anclada abajo, así que al abrirse «Revisión» crece hacia arriba y la 4
   y la 5 quedan prácticamente inmóviles. */
.iscene__band-section--review {
  display: none;
  padding-bottom: calc(var(--divider-h) / 2);
  margin-bottom: calc(var(--divider-h) / 2);
  border-bottom: 1px solid var(--line);
}

.iscene[data-band="review"] .iscene__band-section--review {
  display: block;
}

.iscene__region-label {
  margin: 0 0 calc(var(--label-h) - 0.95rem);
  height: 0.95rem;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- Slots --------------------------------------------------------------- */

.iscene__slot {
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}

.iscene__slot--rail {
  position: relative;
  height: var(--card-h);
}

/* En «Etapa de registro» la franja aloja el archivo en flujo (puede
   ocupar dos líneas en FR), no el abanico de cinco. */
.iscene[data-rail="registro"] .iscene__slot--rail {
  height: auto;
}

/* --- Tarjetas ------------------------------------------------------------ */

.iscene__card {
  height: var(--card-h);
  flex: 0 0 auto;
  box-sizing: border-box;
  padding: 0 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  /* Posición de reposo. FLIP escribe un transform INLINE con el origen del
     vuelo (traslado + la rotación que la tarjeta tenía en su región de
     partida) y lo retira al frame siguiente: la transición interpola hasta
     esta regla, deshaciendo el abanico durante el propio desplazamiento. */
  transform: rotate(var(--rest-rot, 0deg));
  transition: transform var(--move-dur) var(--ease), opacity 0.4s ease,
    border-color 0.3s ease, top 0s;
}

.iscene__card-name {
  font-size: 0.7rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.iscene__card-status {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex: 0 0 auto;
  font-size: 0.64rem;
  font-weight: 700;
  color: var(--ink-secondary);
  white-space: nowrap;
}

.iscene__card[data-status="ready"] {
  border-color: var(--state-ready);
}

.iscene__card[data-status="ready"] .iscene__card-status {
  color: var(--state-ready);
}

.iscene__card[data-status="review"] {
  border-color: var(--state-review);
}

.iscene__card[data-status="review"] .iscene__card-status {
  color: var(--state-review);
}

.iscene__card[data-status="stop"] {
  border-color: var(--state-stop);
  opacity: 0.92;
}

.iscene__card[data-status="stop"] .iscene__card-status {
  color: var(--state-stop);
}

/* Indicador de revisión contenido — sin emoji, sin estética infantil */
.iscene__status-ring {
  display: none;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  border: 2px solid var(--state-review);
  border-top-color: transparent;
  flex-shrink: 0;
  animation: iscene-spin 0.9s linear infinite;
}

.iscene__card[data-status="review"] .iscene__status-ring {
  display: inline-block;
}

@keyframes iscene-spin {
  to {
    transform: rotate(360deg);
  }
}

/* --- Abanico de entrada (etapas 1-2) ------------------------------------- */

/* Cinco documentos apilados en abanico: caben en una franja de una sola
   altura de tarjeta y se leen como "llegó una carpeta". Al cargarse al
   validador se desabanican durante el propio vuelo. */
.iscene[data-rail="entradas"] .iscene__slot--rail .iscene__card {
  position: absolute;
  top: 0;
  width: 54%;
  left: calc(var(--fan-i) * 11.5%);
}

.iscene[data-rail="entradas"] .iscene__slot--rail .iscene__card[data-card="1"] { --fan-i: 0; --rest-rot: -3.5deg; }
.iscene[data-rail="entradas"] .iscene__slot--rail .iscene__card[data-card="2"] { --fan-i: 1; --rest-rot: -1.75deg; }
.iscene[data-rail="entradas"] .iscene__slot--rail .iscene__card[data-card="3"] { --fan-i: 2; --rest-rot: 0deg; }
.iscene[data-rail="entradas"] .iscene__slot--rail .iscene__card[data-card="4"] { --fan-i: 3; --rest-rot: 1.75deg; }
.iscene[data-rail="entradas"] .iscene__slot--rail .iscene__card[data-card="5"] { --fan-i: 4; --rest-rot: 3.5deg; }

/* Aparición inicial (etapa 1): no hay posición previa desde la que viajar,
   así que es la ÚNICA transición de la escena que usa opacity. */
.iscene__card.is-entering {
  opacity: 0;
  transform: translateY(0.45rem) rotate(var(--rest-rot, 0deg));
}

/* --- Validación (etapas 2-5) --------------------------------------------- */

/* El cuerpo ocupa toda la ventana: la lista se lee como una tabla de
   trabajo y deja recorrido real para la agrupación posterior. */
.iscene__slot--tool[data-mode="list"] {
  height: 100%;
  justify-content: flex-start;
}

/* --- Agrupación (etapa 6) ------------------------------------------------ */

/* Las tres aprobadas se aprietan Y se recentran en la ventana: los tres
   objetos siguen siendo tarjetas reconocibles (no se sustituyen todavía
   por nada), pero el bloque se lee como una unidad. Recorrido real de
   decenas de px para cada una, no un reajuste de márgenes. */
.iscene__slot--tool[data-mode="group"] {
  height: 100%;
  gap: 2px;
  justify-content: center;
}

/* --- Abanico de salida + archivo (etapas 7-8) ---------------------------- */

/* Las tres aprobadas se compactan pero siguen siendo tres documentos
   reconocibles: la procedencia del archivo permanece visible. */
.iscene__slot--tool[data-mode="fan"] {
  position: relative;
  height: 100%;
}

.iscene__slot--tool[data-mode="fan"] .iscene__card:not(.iscene__card--archive) {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--fan-i, 0) * var(--card-h) * 0.32);
}

.iscene__slot--tool[data-mode="fan"] .iscene__card[data-card="1"] { --fan-i: 0; }
.iscene__slot--tool[data-mode="fan"] .iscene__card[data-card="2"] { --fan-i: 1; }
.iscene__slot--tool[data-mode="fan"] .iscene__card[data-card="3"] { --fan-i: 2; }

.iscene__slot--tool[data-mode="fan"] .iscene__card--archive {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(2 * var(--card-h) * 0.32 + var(--card-h) + var(--card-gap));
}

/* Una sola línea, siempre: al aterrizar en la franja de registro se le
   suma «✓ Listo», y si envolviera a dos líneas dejaría de caber en la
   franja. El nombre cede espacio con ellipsis antes que romper la caja. */
.iscene__card--archive {
  height: var(--card-h);
  flex-wrap: nowrap;
  border-color: var(--ink);
  border-width: 2px;
}

.iscene__card--archive .iscene__card-name {
  font-size: 0.72rem;
  min-width: 0;
  flex: 0 1 auto;
}

.iscene__card--archive .iscene__card-status {
  flex: 0 0 auto;
}

.iscene__card--archive[hidden] {
  display: none;
}

/* Nace por compactación, no viaja: es un objeto nuevo, no un traslado. */
.iscene__card--archive.is-entering {
  opacity: 0;
  transform: scale(0.85);
}

/* En la etapa de registro el archivo va sobre fondo tinta */
.iscene[data-rail="registro"] .iscene__slot .iscene__card--archive {
  border-color: var(--bg);
  background: transparent;
  color: var(--bg);
}

/* Al aterrizar, «3 facturas» ya se dijo al generarse el archivo (etapa 7):
   aquí lo que importa es el nombre y la confirmación. Ocultarlo evita que
   el nombre se recorte en la franja — «Fichier de chargement» + «✓ Prêt»
   es el caso más largo y cabe holgado en 320px sin el meta. */
.iscene[data-rail="registro"] .iscene__slot--rail .iscene__card--archive .iscene__card-status {
  display: none;
}

.iscene__confirm {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0;
  font-size: 0.64rem;
  font-weight: 700;
  color: var(--bg);
  white-space: nowrap;
}

.iscene__confirm[hidden] {
  display: none;
}

.iscene__confirm-mark {
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 50%;
  background: var(--state-ready);
  color: var(--bg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.55rem;
  flex-shrink: 0;
}

/* --- Escalas mayores ----------------------------------------------------- */

@media (min-width: 23.5rem) {
  .iscene {
    --card-h: 2rem;
    --card-gap: 0.4375rem;
  }
}

@media (min-width: 48rem) {
  .iscene {
    --inset: 0.875rem;
    --region-gap: 0.75rem;
    --region-pad: 0.75rem;
    --card-h: 2.375rem;
    --card-gap: 0.5rem;
    --label-h: 1.4rem;
    --bar-h: 2.25rem;
  }

  .iscene__card-name {
    font-size: 0.82rem;
  }

  .iscene__card-status {
    font-size: 0.74rem;
  }

  .iscene__tool-bar {
    font-size: 0.78rem;
  }

  .iscene__region-label {
    font-size: 0.7rem;
  }
}

@media (min-width: 64rem) {
  .iscene {
    height: clamp(26rem, 56vh, 34rem);
    margin: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .iscene__status-ring {
    animation: none;
    border-top-color: var(--state-review);
    opacity: 0.5;
  }
}

/* --------------------------------------------------------------------------
   Recorrido visual de Soportes — UN SOLO CANVAS ACOTADO, misma técnica que
   .iscene (regiones absolutas de altura constante, objetos persistentes que
   viajan por FLIP) pero con clases y geometría propias: nada de esto toca
   una sola regla de .iscene, y Facturas no referencia ninguna clase .sscene.

   Gramática invertida a propósito frente a Facturas: en vez de "uno entra,
   los demás se reparten en zonas distintas", aquí "varios están separados
   y convergen en un solo punto". Por eso el flujo va de ABAJO hacia ARRIBA:

     .sscene__shelf   «Documentos» (et. 1-4) → 0 (et. 5) — estante de
                      origen; los cinco documentos empiezan aquí
     .sscene__lane    «Revisión» — 0 salvo durante el desvío de ambigüedad
     .sscene__field   ancla la relación de pago (siempre el mismo objeto)
                      y absorbe el resto de la altura, igual que
                      .iscene__tool absorbe el hueco entre rail y band

   El nodo central es UN SOLO OBJETO con UNA sola transformación de
   identidad (texto, no reemplazo de elemento): Relación de pago → Soporte
   de pago listo. No hay una segunda transformación — procesar el pago y
   enviar el comprobante al proveedor son los casos 03/04 y 04/04, no
   este. Los documentos que se unen no desaparecen: pasan a vivir
   apilados detrás de ese nodo (misma técnica de abanico que .iscene,
   aplicada aquí para sugerir "papeles físicamente unidos" en vez de
   "documentos en fila").
   -------------------------------------------------------------------------- */

.sscene {
  --s-inset: 0.625rem;
  --s-region-gap: 0.5rem;
  --s-region-pad: 0.5rem;
  /* Más alta que una ficha de una sola línea: en mobile el nombre y el
     chip se reparten en dos líneas (ver "Tarjetas — mobile" más abajo)
     porque ninguna columna del estante o de "reunidos" tiene ancho para
     las dos cosas en una sola línea sin recortar el nombre. Desktop
     revierte a una sola línea con su propia altura, más generosa. */
  --s-card-h: 2.35rem;
  --s-card-gap: 0.375rem;
  --s-label-h: 1.28rem;
  --s-move-dur: 0.6s;
  --s-ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* Estante: 3 filas (2+2+1) por debajo de 376px — con 3 columnas a ese
     ancho cada ficha quedaba en ~65px, sin sitio real para "Documento N".
     A partir de 376px sube a 2 filas (3+2); en desktop, 1 sola fila. */
  --s-shelf-rows: 3;
  --s-shelf-size: calc(
    var(--s-label-h) + var(--s-shelf-rows) * var(--s-card-h) +
      (var(--s-shelf-rows) - 1) * var(--s-card-gap) + 2 * var(--s-region-pad) +
      0.25rem
  );
  --s-lane-size: calc(var(--s-label-h) + var(--s-card-h) + 2 * var(--s-region-pad) + 0.25rem);

  /* Conmutadas por etapa más abajo. 0 = región colapsada. */
  --s-shelf-h: var(--s-shelf-size);
  --s-shelf-gap: var(--s-region-gap);
  --s-lane-h: 0px;
  --s-lane-gap: 0px;

  position: relative;
  height: clamp(16rem, 50vh, 28rem);
  overflow: hidden;
  margin: var(--space-3) var(--space-3) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.sscene[data-shelf="none"] {
  --s-shelf-h: 0px;
  --s-shelf-gap: 0px;
}

.sscene[data-lane="review"] {
  --s-lane-h: var(--s-lane-size);
  --s-lane-gap: var(--s-region-gap);
}

/* --- Regiones (absolutas, altura fija, overflow oculto) ------------------ */
/* Sin transición de geometría A PROPÓSITO — mismo motivo que .iscene: si
   una región animara su tamaño, el rect que mide FLIP sería el de un
   destino todavía en movimiento y el desplazamiento calculado saldría mal. */

.sscene__shelf,
.sscene__lane {
  position: absolute;
  left: var(--s-inset);
  right: var(--s-inset);
  padding: var(--s-region-pad);
  border-radius: var(--radius-small);
  overflow: hidden;
  transition: opacity 0.3s ease, border-color 0.35s ease;
}

.sscene__shelf {
  bottom: var(--s-inset);
  height: var(--s-shelf-h);
  border: 1px dashed var(--line);
  background: var(--bg);
}

.sscene__lane {
  bottom: calc(var(--s-inset) + var(--s-shelf-h) + var(--s-shelf-gap));
  height: var(--s-lane-h);
  border: 1px solid var(--state-review);
  background: var(--bg);
}

/* Colapsada de verdad: sin padding ni borde, si no conservaría espacio que
   le robaría altura al campo. visibility:hidden además la saca del árbol
   de accesibilidad y garantiza que su contenido no pinte. */
.sscene[data-shelf="none"] .sscene__shelf,
.sscene[data-lane="none"] .sscene__lane {
  opacity: 0;
  visibility: hidden;
  padding: 0;
  border-width: 0;
}

.sscene__region-label {
  margin: 0 0 calc(var(--s-label-h) - 0.95rem);
  height: 0.95rem;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sscene__lane .sscene__region-label {
  color: var(--state-review);
}

/* El campo ABSORBE el resto de la altura — igual técnica que .iscene__tool:
   top/bottom fijos por las otras dos regiones, sin alto propio declarado. */
.sscene__field {
  position: absolute;
  left: var(--s-inset);
  right: var(--s-inset);
  top: var(--s-inset);
  bottom: calc(
    var(--s-inset) + var(--s-shelf-h) + var(--s-shelf-gap) + var(--s-lane-h) +
      var(--s-lane-gap)
  );
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-region-gap);
  overflow: hidden;
}

/* --- Slots ----------------------------------------------------------------
   Contenedores de layout de flujo dentro de cada región — FLIP no depende
   de que el layout sea absoluto, solo diferencia rects antes/después. */

.sscene__anchor {
  position: relative;
  flex: 0 0 auto;
  width: 100%;
  max-width: 14rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sscene__slot--gathered {
  flex: 0 0 auto;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-card-gap);
  min-height: var(--s-card-h);
}

.sscene__slot--lane {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-card-gap);
  height: 100%;
}

/* Grid, no flex-wrap: con flex-wrap la última fila incompleta (2 de 5)
   estira sus tarjetas para llenar el ancho, y quedaban visiblemente más
   anchas que las de la fila completa. El grid mantiene las cinco iguales
   sin importar cuántas caigan en la última fila. */
.sscene__slot--shelf {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-content: start;
  gap: var(--s-card-gap);
  height: 100%;
}

/* --- Tarjetas --------------------------------------------------------------
   Misma estructura que .iscene__card (nombre + estado en línea) pero sin
   compartir una sola regla con ella: familia visual, no herencia técnica. */

.sscene__card {
  box-sizing: border-box;
  height: var(--s-card-h);
  padding: 0 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  transition: transform var(--s-move-dur) var(--s-ease), opacity 0.4s ease,
    border-color 0.3s ease, background-color 0.3s ease, top 0s, left 0s;
}

.sscene__card-name {
  font-size: 0.7rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sscene__card-status {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  flex: 0 0 auto;
  font-size: 0.64rem;
  font-weight: 700;
  color: var(--ink-secondary);
  white-space: nowrap;
}

.sscene__card-ref {
  white-space: nowrap;
}

.sscene__card-flag:empty {
  display: none;
}

/* Documentos: viven en el estante, en reunidos o en revisión. Sin ancho
   propio — cada contexto (grid del estante, fila de reunidos/revisión) se
   lo asigna, así las cinco tarjetas miden igual en cualquier fila. */
.sscene__card--doc {
  min-width: 0;
}

/* Encoge en vez de desbordar: un ancho fijo cabía en el estante (grid de
   3 columnas siempre iguales) pero no en "reunidos", donde 3 tarjetas de
   7.25rem + gaps superaban el ancho del campo a 390px y se salían por el
   borde. flex-shrink las deja compartir el espacio real disponible. */
.sscene__slot--gathered .sscene__card--doc,
.sscene__slot--lane .sscene__card--doc {
  flex: 1 1 0;
  min-width: 0;
  max-width: 9rem;
}

/* Idle: chip visible pero neutro — todavía no se comprobó nada. */
.sscene__card--doc[data-status="idle"] .sscene__card-ref {
  color: var(--ink-secondary);
  opacity: 0.7;
}

/* Match: la búsqueda lo identificó como propio de esta referencia. */
.sscene__card--doc[data-status="match"] {
  border-color: var(--accent);
}

.sscene__card--doc[data-status="match"] .sscene__card-ref {
  color: var(--accent);
  font-weight: 700;
}

/* Excluded: no corresponde (Documento 4) o dejó de ser candidato (el
   descartado de la ambigüedad). Mismo tratamiento para ambos casos — nunca
   es un error, solo "no es de aquí". */
.sscene__card--doc[data-status="excluded"] {
  opacity: 0.55;
}

/* Review: candidato en la franja de ambigüedad. El texto localizado
   sustituye al chip mientras dura — mismo mecanismo que .iscene__card
   cuando su status es "review". */
.sscene__card--doc[data-status="review"] {
  border-color: var(--state-review);
}

.sscene__card--doc[data-status="review"] .sscene__card-ref {
  display: none;
}

.sscene__card--doc[data-status="review"] .sscene__card-flag {
  color: var(--state-review);
}

/* Checked: comprobado. El ✓ antepone al chip, nunca lo sustituye. */
.sscene__card--doc[data-status="checked"] .sscene__card-ref {
  color: var(--state-ready);
  font-weight: 700;
}

.sscene__card--doc[data-status="checked"] .sscene__card-flag {
  color: var(--state-ready);
}

/* --- Relación de pago / Soporte listo --------------------------------------
   El mismo nodo durante las 5 etapas, con UNA sola transformación: no hay
   segunda identidad — procesar el pago y enviar el comprobante son los
   casos 03/04 y 04/04, no este. Más ancho que un documento — es el
   protagonista — y con filete sólido en tinta en vez del filete fino de
   los documentos. */
.sscene__card--pago {
  width: 100%;
  height: calc(var(--s-card-h) + 0.5rem);
  border: 2px solid var(--ink);
  z-index: 5;
  transition: transform 0.5s var(--s-ease), opacity 0.4s ease, border-color 0.3s ease;
}

.sscene__card--pago .sscene__card-name {
  font-size: 0.78rem;
}

.sscene__card--pago[data-identity="support"] {
  border-color: var(--state-ready);
}

.sscene__card--pago[data-identity="support"] .sscene__card-flag {
  color: var(--state-ready);
}

/* Micro-asentamiento en el clímax: el pago desciende brevemente al
   encuentro de los documentos que convergen, en vez de quedarse quieto
   mientras todo lo demás se mueve — ver playPagoSettle() en app.js. */
.sscene__card--pago.is-settling {
  transform: translateY(0.75rem);
}

/* --- Pila unida (etapa 5) -----------------------------------------------
   Los documentos que se unieron viven dentro de .sscene__anchor junto a
   la relación de pago, apilados detrás de ella: mismo principio de
   abanico que .iscene, aplicado aquí para leerse como "papeles
   físicamente unidos" en vez de "documentos en fila". */
.sscene__anchor > .sscene__card:not(.sscene__card--pago) {
  position: absolute;
  width: 88%;
  z-index: calc(4 - var(--fan-i, 0));
  opacity: 0.9;
  transform: translate(
      calc(var(--fan-i, 0) * 0.2rem),
      calc(var(--fan-i, 0) * 0.2rem + 0.35rem)
    )
    scale(calc(1 - var(--fan-i, 0) * 0.03));
}

.sscene__anchor > .sscene__card[data-card="1"] { --fan-i: 0; }
.sscene__anchor > .sscene__card[data-card="2"] { --fan-i: 1; }
.sscene__anchor > .sscene__card[data-card="3a"] { --fan-i: 2; }

/* Aparición inicial (etapa 1): la relación de pago y los documentos
   entran a la vez, sin "de dónde" viajar — igual que .iscene__card.is-entering. */
.sscene__card.is-entering {
  opacity: 0;
  transform: translateY(0.45rem);
}

/* Tarjetas — mobile: nombre y chip en dos líneas, no en una.
   En mobile ninguna columna del estante, ni "reunidos", ni "revisión"
   tiene ancho de sobra para nombre+chip lado a lado sin recortar el
   nombre a 1-2 letras (comprobado: a 320px con layout horizontal el
   nombre se quedaba en ~17px de un ancho de ~65px). Repartirlos en dos
   líneas le da al nombre el ANCHO COMPLETO de la ficha — geometría, no
   tipografía: el tamaño de fuente no cambia en ningún breakpoint mobile.
   Desktop revierte a una sola línea, donde sí sobra ancho real.
   No aplica dentro de .sscene__anchor: ahí las fichas apiladas ya tienen
   sitio de sobra (88% del pago, ~200px) y una sola línea se lee mejor. */
.sscene__slot--shelf .sscene__card,
.sscene__slot--gathered .sscene__card,
.sscene__slot--lane .sscene__card {
  height: var(--s-card-h);
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.05rem;
  padding: 0.2rem 0.45rem;
}

.sscene__slot--shelf .sscene__card-status,
.sscene__slot--gathered .sscene__card-status,
.sscene__slot--lane .sscene__card-status {
  gap: 0.25rem;
}

.sscene__slot--shelf .sscene__card-name,
.sscene__slot--gathered .sscene__card-name,
.sscene__slot--lane .sscene__card-name,
.sscene__slot--shelf .sscene__card-status,
.sscene__slot--gathered .sscene__card-status,
.sscene__slot--lane .sscene__card-status {
  line-height: 1.05;
}

/* La relación de pago en mobile necesita el mismo reparto: "Relación de
   pago" y "Soporte de pago listo" (y sus equivalentes EN/FR) no caben en
   una sola línea junto al chip sin recortarse dentro de los 14rem del
   ancla. Altura propia (no var(--s-card-h) a secas): el pago ya era medio
   rem más alto que un documento y eso se conserva. Revierte a una línea
   en desktop, donde el ancla crece y sí sobra ancho. */
.sscene__card--pago {
  height: calc(var(--s-card-h) + 0.5rem);
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.05rem;
  padding: 0.2rem 0.5rem;
}

.sscene__card--pago .sscene__card-status {
  gap: 0.25rem;
}

.sscene__card--pago .sscene__card-name,
.sscene__card--pago .sscene__card-status {
  line-height: 1.05;
}

/* --- Escalas mayores ------------------------------------------------------ */

@media (min-width: 23.5rem) {
  .sscene {
    --s-card-gap: 0.4375rem;
    --s-shelf-rows: 2;
  }

  .sscene__slot--shelf {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 48rem) {
  .sscene {
    --s-inset: 0.875rem;
    --s-region-gap: 0.75rem;
    --s-region-pad: 0.75rem;
    --s-card-h: 2.375rem;
    --s-card-gap: 0.5rem;
    --s-label-h: 1.4rem;
  }

  .sscene__card-name {
    font-size: 0.82rem;
  }

  .sscene__card-status {
    font-size: 0.74rem;
  }

  .sscene__region-label {
    font-size: 0.7rem;
  }
}

/* Soportes NO adopta la rejilla compartida de copy+canvas a dos columnas
   (esa es la que usa .iscene/Facturas, ver el bloque "Chrome de la
   escena..." más abajo). Con el --content cap del sitio (74rem), esa
   columna de canvas se topaba en ~638px sin importar cuánto creciera la
   ventana, y a esa anchura la composición horizontal interna (estante +
   campo) quedaba apretada y recortaba el ancla — el problema real que
   Juan reportó en 1024px. La solución no es angostar más el estante:
   es dejar de compartir columna con el texto. Por id, porque el
   atributo [data-scene-canvas] es compartido con Facturas y esa regla
   no debe tocarse: la especificidad de un id ya gana sobre
   .scene[data-scene-canvas] sin necesitar !important, así que Facturas
   sigue usando su rejilla exactamente igual. El orden del DOM (cabecera
   → etapa → progreso → canvas → controles) ya es el orden de lectura
   correcto en flujo de bloque, así que no hace falta reordenar nada. */
#scene-soportes,
#scene-backup,
#scene-pieces {
  display: block;
}

/* Convergencia horizontal en vez de vertical, con el canvas usando el
   ANCHO COMPLETO del caso — no una columna compartida — pero acotado por
   su propio max-width: en monitores muy anchos, más sitio no es mejor
   composición, es "Factura 1" a 700px de la relación de pago. El estante
   es un panel COMPACTO a la izquierda (mismo grid de 2 columnas que ya
   funciona en mobile angosto, aquí por elección de composición); Revisión
   es un panel intermedio que solo existe durante la ambigüedad; el
   campo —con el ancla, más grande— ocupa la derecha. Mismo calc-chain de
   siempre (una región fija empuja a la que sigue), aplicado a left/width
   en vez de bottom/height. FLIP no distingue: solo mide rects antes/
   después, así que el salto de vertical a horizontal es puramente CSS —
   ningún dato de etapa ni de zona cambia. */
@media (min-width: 64rem) {
  .sscene {
    /* Estable, no fluido: al no compartir columna con el texto, el
       ancho del canvas ya no fluctúa entre ~489 y ~638px según el
       viewport — se topa en su propio max-width y se mantiene ahí, así
       que el estante y el campo pueden usar valores fijos en vez de
       clamp(vw). Centrado con margin:auto dentro del ancho completo del
       caso. Más baja que .iscene a propósito: el contenido de Soportes
       (un montón de 2×3 documentos, un ancla, tres reunidos) nunca
       necesitó la misma altura que el carril+ventana+franja de
       Facturas. */
    max-width: 44rem;
    margin: var(--space-5) auto 0;
    height: clamp(20rem, 40vh, 26rem);
    --s-shelf-rows: 3;
    --s-shelf-w: 0px;
    --s-lane-w: 0px;
  }

  .sscene[data-shelf="open"] {
    --s-shelf-w: 14rem;
  }

  /* Angosta a propósito: como Revisión se posa encima del campo (ver
     abajo) en vez de empujarlo, cuanto menos invada mejor. Apilar los dos
     candidatos en vertical (columna, igual que en mobile — sin el
     flex-direction:row de antes) le basta con el ancho de UNA ficha en
     vez de dos lado a lado, y así casi no llega a tocar el ancla. */
  .sscene[data-lane="review"] {
    --s-lane-w: 8rem;
  }

  .sscene__slot--shelf {
    grid-template-columns: repeat(2, 1fr);
    align-content: center;
  }

  .sscene__shelf,
  .sscene__lane,
  .sscene__field {
    top: var(--s-inset);
    bottom: var(--s-inset);
    height: auto;
  }

  .sscene__shelf {
    left: var(--s-inset);
    right: auto;
    width: var(--s-shelf-w);
  }

  /* Revisión NO empuja al campo — a diferencia del estante, que solo
     convive con el campo (nunca con la franja: para cuando aparecen los
     dos candidatos el estante ya solo guarda al excluido). Sumar los dos
     anchos dejaba el campo en ~90px y recortaba el ancla. En vez de
     empujar, la franja se posa ENCIMA del arranque del campo —mismo
     fondo opaco, sombra para leerse como una capa que aterrizó— durante
     los ~1300ms que dura la ambigüedad. El campo ni se entera: su `left`
     ya no depende de --s-lane-w, así que su posición es IDÉNTICA en
     todas las demás etapas — cero riesgo de regresión fuera del desvío. */
  .sscene__lane {
    /* Centrada en la costura estante/campo: 70% de su ancho cae sobre el
       tramo que antes ocupaba el gap (o sobre el estante, que para este
       momento ya solo guarda al excluido), y solo ~30% asoma sobre el
       borde del campo — nunca sobre el centro, que es donde vive el
       ancla. */
    left: calc(
      var(--s-inset) + var(--s-shelf-w) + var(--s-shelf-gap) - var(--s-lane-w) * 0.7
    );
    right: auto;
    width: var(--s-lane-w);
    z-index: 4;
    box-shadow: 0 0.5rem 1.5rem rgba(16, 16, 20, 0.14);
  }

  /* Dos candidatos apilados, no lado a lado: la franja solo necesita el
     ancho de UNA ficha (ver --s-lane-w arriba). */
  .sscene__slot--lane {
    flex-direction: column;
  }

  .sscene__field {
    left: calc(var(--s-inset) + var(--s-shelf-w) + var(--s-shelf-gap));
    right: var(--s-inset);
    /* Más aire entre el ancla y "reunidos" que en mobile: en un panel
       ancho, la separación entre las dos zonas del campo debe leerse
       como una decisión, no como el mismo gap ajustado de una columna
       estrecha. */
    gap: 1.25rem;
  }

  /* El protagonista gana presencia real: en mobile 14rem ya llenaba el
     ancho disponible; en desktop, con la derecha para él solo, puede
     crecer sin competir con el estante. */
  .sscene__anchor {
    max-width: 19rem;
  }

  .sscene__card--pago .sscene__card-name {
    font-size: 0.92rem;
  }

  /* Con el ancla a 19rem y el campo solo para ella, vuelve a sobrar ancho
     real: nombre y chip caben lado a lado, como en el resto del sitio. */
  .sscene__card--pago {
    height: calc(var(--s-card-h) + 0.5rem);
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    padding: 0 0.6rem;
  }

  .sscene__card--pago .sscene__card-name,
  .sscene__card--pago .sscene__card-status {
    line-height: inherit;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sscene__card--pago.is-settling {
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   Recorrido visual de Pagos — UN SOLO CANVAS ACOTADO, misma técnica que
   .iscene y .sscene (regiones absolutas, altura total constante, objetos
   persistentes que viajan por FLIP) pero con clases, geometría y gramática
   propias: no comparte una sola regla con ninguna de las otras dos.

   La gramática NO es el reparto en zonas de Facturas ni la convergencia de
   Soportes. Aquí hay UNA COLA y UNA SALIDA, y la salida está cerrada
   mientras quede un problema dentro de la cola:

     .pscene__queue  «Pagos por procesar» → «Pagos validados». Absorbe toda
                     la altura que no ocupa la salida y contiene DENTRO DE SÍ
                     MISMA la sub-zona «Apartado» — por eso apartar un pago
                     nunca cambia la altura del canvas: la tarjeta sale de la
                     cola y entra en la sub-zona del mismo recuadro.
     .pscene__gate   la salida. Barra permanente, anclada abajo, presente en
                     las 8 etapas — es el único objeto que nunca se colapsa,
                     y el que transforma su identidad al final:
                     nada preparado → no puede procesarse → sin problemas
                     pendientes → archivo listo para procesar.

   Ningún estado depende solo del color: cada tarjeta lleva SIEMPRE una
   palabra de estado, y el pago apartado además se mueve físicamente.
   -------------------------------------------------------------------------- */

.pscene {
  --p-inset: 0.625rem;
  --p-region-gap: 0.5rem;
  --p-region-pad: 0.5rem;
  /* Dos líneas por tarjeta en mobile (referencia+estado / proveedor+importe):
     ninguna columna de 320px tiene ancho para las cuatro cosas en una sola
     línea sin dejar el nombre del proveedor en tres letras. A partir de
     48rem pasa a una sola línea, donde sí sobra ancho real. */
  --p-card-h: 2.15rem;
  --p-card-gap: 0.35rem;
  --p-label-h: 1.28rem;
  /* Fija en todas las etapas: en «archivo listo» la salida gana una segunda
     línea (el conteo) y no debe cambiar de alto al ganarla. */
  --p-gate-h: 3.1rem;
  --p-move-dur: 0.58s;
  --p-ease: cubic-bezier(0.4, 0, 0.2, 1);

  position: relative;
  /* Más alta que .iscene/.sscene a propósito: los cinco pagos se leen en
     columna y tienen que estar los cinco a la vista a la vez — es la única
     forma de ver que dos comparten la misma referencia. */
  height: clamp(21rem, 60vh, 29rem);
  overflow: hidden;
  margin: var(--space-3) var(--space-3) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/* --- Regiones ------------------------------------------------------------ */
/* Sin transición de geometría A PROPÓSITO — mismo motivo que en .iscene y
   .sscene: si una región animara su tamaño, el rect que mide FLIP sería el
   de un destino todavía en movimiento. Solo se animan las tarjetas. */

.pscene__queue {
  position: absolute;
  left: var(--p-inset);
  right: var(--p-inset);
  top: var(--p-inset);
  bottom: calc(var(--p-inset) + var(--p-gate-h) + var(--p-region-gap));
  padding: var(--p-region-pad);
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: border-color 0.35s ease;
}

.pscene[data-gate="file"] .pscene__queue {
  border-color: var(--state-ready);
}

.pscene__region-label {
  flex: 0 0 auto;
  margin: 0 0 calc(var(--p-label-h) - 0.95rem);
  height: 0.95rem;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pscene__slot--queue {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--p-card-gap);
}

/* La sub-zona vive DENTRO de la cola y se ancla a su borde inferior
   (margin-top:auto). Al abrirse, la cola ya tiene un pago menos, así que la
   suma cabe en el mismo recuadro sin que el canvas cambie de alto. */
.pscene__aside {
  display: none;
  margin-top: auto;
  padding-top: var(--p-region-pad);
  border-top: 1px dashed var(--line);
}

.pscene[data-aside="open"] .pscene__aside {
  display: block;
}

.pscene__aside .pscene__region-label {
  color: var(--state-stop);
}

.pscene__slot--aside {
  display: flex;
  flex-direction: column;
  gap: var(--p-card-gap);
}

/* --- Tarjetas de pago ---------------------------------------------------- */
/* Rejilla de dos filas en mobile, de una sola fila desde 48rem. Las cuatro
   piezas son hijos directos: así el cambio de composición es solo
   grid-template-areas, sin envoltorios que reordenar. */

.pscene__card {
  box-sizing: border-box;
  height: var(--p-card-h);
  flex: 0 0 auto;
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  display: grid;
  /* Tres columnas, no dos: con dos, el estado («Referencia en double» es el
     caso más largo) y el importe compartían columna, y el estado más largo
     estrujaba el nombre del proveedor justo en las tarjetas problemáticas
     —las que más importa leer—. Haciendo que el estado ocupe las columnas
     2-3 y el nombre las 1-2, solo el importe fija el ancho de la derecha:
     el nombre recupera ~50% de ancho a 320px sin cambiar de tipografía. */
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "ref  flag flag"
    "name name amount";
  align-content: center;
  column-gap: 0.4rem;
  row-gap: 0.05rem;
  transition: transform var(--p-move-dur) var(--p-ease), opacity 0.4s ease,
    border-color 0.3s ease, background-color 0.3s ease;
}

.pscene__card-ref {
  grid-area: ref;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.05;
  white-space: nowrap;
  justify-self: start;
}

.pscene__card-flag {
  grid-area: flag;
  justify-self: end;
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1.05;
  color: var(--ink-secondary);
  white-space: nowrap;
}

.pscene__card-flag:empty {
  display: none;
}

.pscene__card-name {
  grid-area: name;
  min-width: 0;
  font-size: 0.62rem;
  font-weight: 600;
  line-height: 1.05;
  color: var(--ink-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pscene__card-amount {
  grid-area: amount;
  justify-self: end;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1.05;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* --- Estados de la tarjeta ------------------------------------------------ */

.pscene__card[data-status="checking"] {
  border-color: var(--ink-secondary);
}

.pscene__card[data-status="ok"] {
  border-color: var(--state-ready);
}

.pscene__card[data-status="ok"] .pscene__card-flag {
  color: var(--state-ready);
}

.pscene__card[data-status="fix"] {
  border-color: var(--state-review);
}

.pscene__card[data-status="fix"] .pscene__card-flag {
  color: var(--state-review);
}

.pscene__card[data-status="dup"] {
  border-color: var(--state-stop);
}

.pscene__card[data-status="dup"] .pscene__card-flag {
  color: var(--state-stop);
}

.pscene__card[data-status="aside"] {
  border-color: var(--state-stop);
  border-style: dashed;
  opacity: 0.62;
}

.pscene__card[data-status="aside"] .pscene__card-flag {
  color: var(--state-stop);
}

/* Las DOS referencias iguales se subrayan a la vez mientras dura el
   conflicto: el subrayado las relaciona (es el mismo dato), el color las
   distingue (una ya estaba registrada, la otra es la que no puede pasar).
   Sin el subrayado en la primera, el visitante tendría que buscar por su
   cuenta de dónde sale «repetida». */
.pscene__card[data-echo="on"] .pscene__card-ref,
.pscene__card[data-status="dup"] .pscene__card-ref {
  box-shadow: inset 0 -0.12rem 0 currentColor;
}

.pscene__card[data-echo="on"] .pscene__card-ref {
  color: var(--accent);
}

.pscene__card[data-status="dup"] .pscene__card-ref {
  color: var(--state-stop);
}

/* Aparición inicial (etapa 1): los cinco ya están en la cola, no hay "de
   dónde" viajar — única transición de la escena que usa opacity. */
.pscene__card.is-entering {
  opacity: 0;
  transform: translateY(0.45rem);
}

/* --- La salida ------------------------------------------------------------ */
/* Presente en las ocho etapas, nunca colapsa. Es la pieza que responde al
   estado de la cola, así que es también la que cuenta la historia. */

.pscene__gate {
  position: absolute;
  left: var(--p-inset);
  right: var(--p-inset);
  bottom: var(--p-inset);
  height: var(--p-gate-h);
  padding: 0 0.65rem;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  transition: border-color 0.35s ease, background-color 0.35s ease,
    transform 0.3s var(--p-ease);
}

.pscene__gate-mark {
  flex: 0 0 auto;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  border: 2px solid var(--line);
  background: transparent;
  color: var(--bg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.62rem;
  line-height: 1;
  transition: border-color 0.35s ease, background-color 0.35s ease;
}

.pscene__gate-body {
  display: grid;
  gap: 0.1rem;
  min-width: 0;
}

.pscene__gate-text {
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.2;
}

.pscene__gate-meta {
  font-size: 0.62rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink-secondary);
}

.pscene__gate-meta[hidden] {
  display: none;
}

.pscene[data-gate="blocked"] .pscene__gate {
  border-style: solid;
  border-color: var(--state-stop);
}

.pscene[data-gate="blocked"] .pscene__gate-text {
  color: var(--state-stop);
}

.pscene[data-gate="blocked"] .pscene__gate-mark {
  border-color: var(--state-stop);
  background: var(--state-stop);
}

.pscene[data-gate="blocked"] .pscene__gate-mark::before {
  content: '';
  width: 0.5rem;
  height: 0.14rem;
  border-radius: 999px;
  background: var(--bg);
}

.pscene[data-gate="clear"] .pscene__gate {
  border-style: solid;
  border-color: var(--state-ready);
}

.pscene[data-gate="clear"] .pscene__gate-text {
  color: var(--state-ready);
}

.pscene[data-gate="clear"] .pscene__gate-mark {
  border-color: var(--state-ready);
  background: var(--state-ready);
}

.pscene[data-gate="clear"] .pscene__gate-mark::before,
.pscene[data-gate="processed"] .pscene__gate-mark::before {
  content: '✓';
}

/* Archivo y portal comparten el mismo tratamiento visual (tinta sólida):
   son el MISMO objeto en tránsito hacia el banco, todavía no es el cierre
   del caso. Solo "procesados" rompe a verde — ese es el resultado real. */
.pscene[data-gate="file"] .pscene__gate,
.pscene[data-gate="portal"] .pscene__gate {
  border-style: solid;
  border-color: var(--ink);
  background: var(--ink);
}

.pscene[data-gate="file"] .pscene__gate-text,
.pscene[data-gate="portal"] .pscene__gate-text {
  color: var(--bg);
}

.pscene[data-gate="file"] .pscene__gate-meta,
.pscene[data-gate="portal"] .pscene__gate-meta {
  color: var(--bg);
  opacity: 0.75;
}

.pscene[data-gate="file"] .pscene__gate-mark {
  border-color: var(--state-ready);
  background: var(--state-ready);
}

/* Portal: flecha de carga, no marca de éxito todavía — el archivo está en
   camino, no procesado. */
.pscene[data-gate="portal"] .pscene__gate-mark {
  border-color: var(--bg);
  background: transparent;
}

.pscene[data-gate="portal"] .pscene__gate-mark::before {
  content: '↑';
  color: var(--bg);
  font-size: 0.7rem;
  line-height: 1;
}

/* Procesados: única vez que la barra vuelve a verde después del archivo —
   marca que el resultado ya es real, no solo que el archivo quedó listo. */
.pscene[data-gate="processed"] .pscene__gate {
  border-style: solid;
  border-color: var(--state-ready);
}

.pscene[data-gate="processed"] .pscene__gate-text {
  color: var(--state-ready);
}

.pscene[data-gate="processed"] .pscene__gate-mark {
  border-color: var(--state-ready);
  background: var(--state-ready);
}

/* Micro-acento en los momentos en que la salida cambia de significado:
   se cierra, se abre, se materializa el archivo o llega el resultado final.
   Portal queda fuera a propósito — es continuación silenciosa de la misma
   barra, no un nuevo evento. Ver playGatePulse() en app.js. */
.pscene__gate.is-blocking {
  transform: translateY(0.28rem);
}

.pscene__gate.is-opening {
  transform: translateY(-0.28rem);
}

/* --- Escalas mayores ----------------------------------------------------- */

@media (min-width: 23.5rem) {
  .pscene {
    --p-card-h: 2.4rem;
    --p-card-gap: 0.4rem;
  }

  .pscene__card-ref {
    font-size: 0.72rem;
  }

  .pscene__card-flag {
    font-size: 0.64rem;
  }

  .pscene__card-name,
  .pscene__card-amount {
    font-size: 0.66rem;
  }
}

/* Una sola línea por pago: a partir de tablet el canvas ya tiene ancho real
   para referencia + proveedor + importe + estado sin recortar el nombre. */
@media (min-width: 48rem) {
  .pscene {
    --p-inset: 0.875rem;
    --p-region-gap: 0.75rem;
    --p-region-pad: 0.75rem;
    --p-card-h: 2.6rem;
    --p-card-gap: 0.5rem;
    --p-label-h: 1.4rem;
    --p-gate-h: 3.4rem;
  }

  .pscene__card {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas: "ref name amount flag";
    align-items: center;
    column-gap: 0.85rem;
    row-gap: 0;
    padding: 0 0.75rem;
  }

  .pscene__card-ref,
  .pscene__card-flag,
  .pscene__card-name,
  .pscene__card-amount {
    line-height: 1.3;
  }

  .pscene__card-name,
  .pscene__card-amount {
    font-size: 0.78rem;
  }

  .pscene__card-ref {
    font-size: 0.8rem;
  }

  .pscene__card-flag {
    font-size: 0.72rem;
  }

  .pscene__region-label {
    font-size: 0.7rem;
  }

  .pscene__gate-text {
    font-size: 0.85rem;
  }

  .pscene__gate-meta {
    font-size: 0.7rem;
  }

  .pscene__gate {
    padding: 0 0.9rem;
    gap: 0.7rem;
  }

  .pscene__gate-mark {
    width: 1.3rem;
    height: 1.3rem;
  }
}

/* Pagos NO adopta la rejilla compartida de copy+canvas a dos columnas —
   mismo diagnóstico y misma solución que Soportes (ver el bloque de
   #scene-soportes más arriba): con el --content cap del sitio, esa columna
   de canvas se topa en ~500-640px sin importar cuánto crezca la ventana, y
   a esa anchura las CUATRO piezas de cada tarjeta (referencia, proveedor,
   importe, estado) en una sola línea quedaban comprimidas — la escena se
   leía "completa" (sin overflow, sin recortes) pero apretada, sin el aire
   que sí tiene en mobile. La solución es la misma: dejar de compartir
   columna con el texto y centrar el canvas en un ancho propio. Por id,
   mismo motivo que Soportes: [data-scene-canvas] es compartido con
   Facturas y esa regla no debe tocarse. */
#scene-pagos,
#scene-payments,
#scene-paiements {
  display: block;
}

/* Ancho propio, más angosto que el de Soportes a propósito: el contenido
   de Pagos es una lista de filas de texto, no un panel con documentos
   apilados — un ancho mayor solo alargaría cada fila con aire vacío entre
   sus cuatro piezas. 38rem es el punto donde "Proveedor Mantenimiento" +
   importe + estado más largo ("Referencia repetida") conviven con
   holgura real sin que la fila se lea desproporcionada. Centrado con
   margin:auto, igual que Soportes — estable en vez de fluido: ya no
   fluctúa con el viewport, se topa en su propio max-width y se queda ahí. */
@media (min-width: 64rem) {
  .pscene {
    max-width: 38rem;
    margin: var(--space-5) auto 0;
    height: clamp(28rem, 46vh, 32rem);
    --p-card-h: 2.85rem;
    --p-region-pad: 0.9rem;
    --p-gate-h: 3.6rem;
  }

  .pscene__card {
    column-gap: 0.9rem;
    padding: 0 0.9rem;
  }

  .pscene__card-ref {
    font-size: 0.85rem;
  }

  .pscene__card-name,
  .pscene__card-amount {
    font-size: 0.8rem;
  }

  .pscene__card-flag {
    font-size: 0.74rem;
  }

  .pscene__region-label {
    font-size: 0.72rem;
  }

  .pscene__gate-text {
    font-size: 0.92rem;
  }

  .pscene__gate-meta {
    font-size: 0.74rem;
  }

  .pscene__gate {
    padding: 0 1rem;
    gap: 0.75rem;
  }

  .pscene__gate-mark {
    width: 1.4rem;
    height: 1.4rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pscene__gate.is-blocking,
  .pscene__gate.is-opening {
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   Recorrido visual de Correos — gramática propia, la única que DIVERGE en
   vez de converger: Facturas/Soportes/Pagos reparten, reúnen o bloquean
   varias entradas hasta dejar UNA salida (un archivo, un soporte, un
   portal). Aquí una lista entra y SALEN VARIAS COSAS DISTINTAS, hacia fuera
   de la empresa — el único caso del sitio donde el resultado abandona el
   canvas hacia personas, no hacia un objeto que se queda.

   LA FILA NO VIAJA: SE TRANSFORMA. A diferencia de .iscene/.sscene/.pscene,
   los cuatro proveedores son cuatro nodos que NUNCA cambian de contenedor
   ni de posición — solo cambian de contenido y de tamaño en su propio
   sitio. Por eso esta escena no necesita FLIP (medir antes/después y
   animar la diferencia): toda la animación reacciona a atributos de datos
   con transiciones CSS puras, y EmailScene (app.js) solo escribe esos
   atributos.

     .cscene__panel  «Catálogo» (etapa 2) → «Documentos» (etapa 3) → 0
                     (etapas 1 y 4-7) — mismo marco, contenido distinto,
                     igual principio que .iscene__tool cambiando de rótulo.
     .cscene__list   las cuatro filas. Ninguna sale de aquí — a diferencia
                     de Pagos, donde el pago con error se aparta físicamente.
     .cscene__result barra de resultado, SIEMPRE presente (igual que
                     .pscene__gate) para que su aparición nunca desplace a
                     las filas: «envío» → «enviando…» → «4 correos
                     enviados · historial actualizado».

   Por decisión de Juan (revisión de reorientación de diseño), esta versión
   NO usa validaciones como protagonistas: las cuatro filas siempre
   encuentran su destinatario y su documento. La credibilidad no viene de
   un error resuelto en escena sino del TAMAÑO DE LA BÚSQUEDA — el catálogo
   tiene más entradas que las cuatro necesarias (relleno sin texto real,
   solo para leerse como «hay más»), y la carpeta de documentos muestra
   ocho referencias de las que solo cuatro corresponden. Ningún estado
   depende solo del color: cada tarjeta lleva siempre una etiqueta de texto
   («—», «Enviado ✓»…).

   7 etapas; cada índice reconstruye el recorrido completo de forma
   determinista, igual que INVOICE_PLANS/SUPPORT_PLANS/PAYMENT_PLANS:
   goToStage(index) solo aplica la tabla correspondiente. -------------- */

.cscene {
  --c-inset: 0.625rem;
  --c-gap: 0.5rem;
  --c-region-pad: 0.5rem;
  --c-row-h: 3.5rem;
  --c-row-h-compact: 1.5rem;
  /* Piso, no techo: con De/Para/CC/Asunto + saludo + dos párrafos + firma
     + adjunto, el contenido real casi siempre supera este mínimo y la
     fila crece por su propio contenido (sin overflow en la fila misma,
     solo min-height) — ver el ajuste de altura del canvas más abajo. */
  --c-row-h-expanded: 17rem;
  --c-result-h: 2.85rem;
  --c-panel-h: 0px;
  --c-panel-gap: 0px;
  --c-panel-w: 0px;
  --c-ease: cubic-bezier(0.4, 0, 0.2, 1);

  position: relative;
  /* El mínimo no es cosmético. Con el panel activo (etapas 2-3), inset +
     panel + las cuatro filas + resultado ya necesitaban margen; con el
     correo real de la etapa 5 (encabezado De/Para/CC/Asunto + saludo +
     dos párrafos + firma + adjunto) la fila ampliada sola mide ~17.5rem,
     y es ella —no el panel— la que fija el mínimo real a 320px de ancho.
     Por debajo de esto el overflow:hidden de la lista recortaba la
     tarjeta. Sin panel activo y sin ampliar (etapas 1, 4, 6-7) sobra
     margen: es el precio de una altura constante en las siete etapas. */
  height: clamp(30rem, 56vh, 30.5rem);
  overflow: hidden;
  margin: var(--space-3) var(--space-3) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--c-inset);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--c-panel-h) minmax(0, 1fr) var(--c-result-h);
  grid-template-areas: "panel" "list" "result";
  row-gap: 0;
}

.cscene[data-panel="catalog"],
.cscene[data-panel="docs"] {
  --c-panel-h: 6.6rem;
  --c-panel-gap: var(--c-gap);
}

/* --- Panel transitorio: Catálogo → Documentos --------------------------- */
/* Sin transición de geometría, mismo motivo que en .iscene/.sscene/.pscene:
   si el panel animara su tamaño, un contenido en tránsito mediría un
   destino todavía en movimiento. Aquí no hay FLIP, pero se conserva la
   misma regla por consistencia — solo el CONTENIDO cruza en fundido. */

.cscene__panel {
  grid-area: panel;
  position: relative;
  overflow: hidden;
  margin-bottom: var(--c-panel-gap);
  border: 1px dashed var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
}

.cscene__panel-view {
  position: absolute;
  inset: 0;
  padding: 0.4rem var(--c-region-pad);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.cscene[data-panel="catalog"] [data-panel-view="catalog"],
.cscene[data-panel="docs"] [data-panel-view="docs"] {
  opacity: 1;
  visibility: visible;
}

.cscene__panel-title {
  flex: 0 0 auto;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-secondary);
}

.cscene__cat-list {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  overflow: hidden;
  /* El degradado inferior es la única prueba de que hay más filas de las
     que caben — nunca una cifra real. */
  -webkit-mask-image: linear-gradient(to bottom, #000 76%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 76%, transparent 100%);
}

.cscene__cat-row {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  height: 0.95rem;
  font-size: 0.58rem;
}

.cscene__cat-row--match {
  font-weight: 600;
}

.cscene__cat-name {
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cscene__cat-address {
  flex: 0 0 auto;
  color: var(--ink-secondary);
  font-size: 0.56rem;
}

/* Relleno decorativo sin texto real — el catálogo tiene más proveedores
   que los cuatro necesarios; sus nombres no importan al caso. */
.cscene__cat-row--filler {
  height: 0.55rem;
  border-radius: 999px;
  background: var(--line);
  opacity: 0.6;
}

.cscene__chip-grid {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.3rem;
  align-content: start;
}

.cscene__chip {
  padding: 0.2rem 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  text-align: center;
  font-size: 0.56rem;
  font-weight: 600;
  color: var(--ink-secondary);
}

.cscene__chip--match {
  border-color: var(--accent);
  color: var(--accent);
}

/* --- Las cuatro filas: nunca cambian de contenedor ---------------------- */

.cscene__list {
  grid-area: list;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.4rem;
  min-height: 0;
  overflow: hidden;
  /* Mismo mecanismo que el margen inferior del panel: sin fila de grid
     dedicada al espacio "lista → resultado", este margen es lo único que
     garantiza aire entre la última fila y la barra, sobre todo cuando el
     contenido llena casi todo el alto del track (etapas 2-3 en desktop). */
  margin-bottom: var(--c-gap);
}

.cscene__row {
  position: relative;
  flex: 0 0 auto;
  min-height: var(--c-row-h);
  padding: 0.9rem 0.55rem 0.35rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  justify-content: center;
  transition: min-height 0.4s var(--c-ease), opacity 0.35s ease,
    border-color 0.3s ease, padding 0.35s var(--c-ease);
}

.cscene__row.is-entering {
  opacity: 0;
  transform: translateY(0.4rem);
}

.cscene__row-tag {
  position: absolute;
  top: 0.3rem;
  left: 0.55rem;
  font-size: 0.56rem;
  font-weight: 700;
  color: var(--ink-secondary);
}

.cscene__flip-wrap {
  perspective: 60rem;
}

.cscene__flip {
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.5s var(--c-ease);
}

.cscene__row[data-status="message"] .cscene__flip,
.cscene__row[data-status="sent"] .cscene__flip {
  transform: rotateX(180deg);
}

.cscene__face {
  backface-visibility: hidden;
}

.cscene__face--message {
  position: absolute;
  inset: 0;
  transform: rotateX(180deg);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.cscene__row-name {
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.05rem;
}

.cscene__row-line {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  line-height: 1.25;
}

.cscene__row-label {
  flex: 0 0 auto;
  font-size: 0.58rem;
  font-weight: 700;
  color: var(--ink-secondary);
}

.cscene__row-value {
  min-width: 0;
  font-size: 0.62rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cscene__row-real {
  display: none;
}

.cscene__row-ph {
  color: var(--ink-secondary);
  font-weight: 500;
}

/* Placeholder → valor real: sin manipular texto por JS, las dos versiones
   ya están en el HTML de cada idioma y la visible depende solo del
   estado. La dirección aparece desde "address"; el documento, desde
   "ready" — un paso después, porque son dos búsquedas distintas. */
.cscene__row:is([data-status="address"], [data-status="ready"], [data-status="message"], [data-status="sent"])
  .cscene__row-value--address
  .cscene__row-real {
  display: inline;
}

.cscene__row:is([data-status="address"], [data-status="ready"], [data-status="message"], [data-status="sent"])
  .cscene__row-value--address
  .cscene__row-ph {
  display: none;
}

.cscene__row:is([data-status="ready"], [data-status="message"], [data-status="sent"])
  .cscene__row-value--doc
  .cscene__row-real {
  display: inline;
}

.cscene__row:is([data-status="ready"], [data-status="message"], [data-status="sent"])
  .cscene__row-value--doc
  .cscene__row-ph {
  display: none;
}

.cscene__row-greet {
  font-size: 0.64rem;
  font-weight: 600;
  line-height: 1.3;
}

.cscene__badge {
  position: absolute;
  top: 0.3rem;
  right: 0.5rem;
  font-size: 0.56rem;
  font-weight: 700;
  color: var(--state-ready);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.cscene__row[data-status="sent"] .cscene__badge {
  opacity: 1;
}

/* --- Ampliado: siempre la misma tarjeta (Proveedor Alimentos) ----------- */
/* No es una elección dinámica de la escena — es la que mejor respira en
   mobile (nombre y dirección más cortos de las cuatro). */

.cscene__expanded {
  display: none;
  flex-direction: column;
  gap: 0.3rem;
}

.cscene__row[data-focus="true"] .cscene__expanded {
  display: flex;
}

.cscene__row[data-focus="true"] .cscene__flip-wrap {
  display: none;
}

/* La referencia ya vive en la línea de adjunto del correo real — la
   etiqueta fija de la esquina sobra y compite con la cabecera. */
.cscene__row[data-focus="true"] .cscene__row-tag {
  display: none;
}

.cscene__row[data-focus="true"] {
  min-height: var(--c-row-h-expanded);
  border-color: var(--accent);
  align-items: stretch;
}

.cscene__expanded-brand {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.66rem;
  font-weight: 700;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid var(--line);
}

.cscene__expanded-mark {
  display: inline-block;
  flex: 0 0 auto;
  width: 1.05rem;
  height: 1.05rem;
  color: var(--accent);
}

/* Cabecera de correo real: De / Para / CC / Asunto, una línea cada una.
   Gap más cerrado que el resto de líneas de la escena porque aquí son
   cuatro seguidas y deben leerse como un bloque, no como filas sueltas. */
.cscene__expanded-meta {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid var(--line);
}

.cscene__expanded-meta .cscene__row-label {
  min-width: 2.5rem;
}

.cscene__expanded-body {
  font-size: 0.64rem;
  line-height: 1.4;
  color: var(--ink-secondary);
}

.cscene__expanded-sign {
  font-size: 0.64rem;
  line-height: 1.35;
  color: var(--ink-secondary);
}

/* --- Adjunto: se lee como un archivo real, no como un dato de texto ----- */

.cscene__attach {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding-top: 0.35rem;
  border-top: 1px dashed var(--line);
}

.cscene__pdf-icon {
  flex: 0 0 auto;
  width: 1.6rem;
  height: 1.6rem;
  color: var(--state-stop);
}

.cscene__attach-text {
  display: flex;
  flex-direction: column;
  gap: 0.02rem;
  min-width: 0;
}

.cscene__attach-name {
  font-size: 0.62rem;
  font-weight: 600;
  color: var(--ink);
  white-space: normal;
}

.cscene__attach-file {
  font-size: 0.6rem;
  font-weight: 600;
  color: var(--ink-secondary);
  font-variant-numeric: tabular-nums;
}

/* --- Las tres hermanas se ocultan mientras una se amplía ---------------- */
/* La escena ya dejó claro que existen cuatro (etapas 1-4); en la 5 el foco
   es un único correo, sin compañía ni versión atenuada — se ocultan del
   todo y vuelven en la 6, cuando se envían los cuatro. */

.cscene__list[data-any-focus="true"] .cscene__row:not([data-focus="true"]) {
  display: none;
}

/* --- Envío: aquí SÍ un impulso escalonado, porque ocurre así de verdad -- */

@keyframes cscene-pulse {
  0% { transform: translateY(0); }
  40% { transform: translateY(-0.3rem); }
  100% { transform: translateY(0); }
}

.cscene__row.is-sending {
  animation: cscene-pulse 0.5s ease;
}

/* --- Resultado: siempre presente, nunca desplaza a las filas ------------ */

.cscene__result {
  grid-area: result;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.05rem;
  padding: 0 0.65rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-small);
  background: var(--bg);
  transition: border-color 0.35s ease, background-color 0.35s ease;
}

.cscene__result-text {
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.2;
}

.cscene__result-meta {
  font-size: 0.6rem;
  font-weight: 600;
  color: var(--ink-secondary);
}

.cscene__result-meta[hidden] {
  display: none;
}

.cscene[data-result="sending"] .cscene__result {
  border-style: solid;
  border-color: var(--ink);
}

.cscene[data-result="sent"] .cscene__result {
  border-style: solid;
  border-color: var(--state-ready);
}

.cscene[data-result="sent"] .cscene__result-text {
  color: var(--state-ready);
}

/* --- Escalas mayores ----------------------------------------------------- */

@media (min-width: 23.5rem) {
  .cscene {
    --c-row-h: 3.8rem;
    /* Mismo motivo que el mínimo base: la fila ampliada de la etapa 5 fija
       el piso real (~29.5rem a este ancho), no el panel de las etapas 2-3. */
    height: clamp(29.5rem, 56vh, 30rem);
  }

  .cscene__row-name {
    font-size: 0.72rem;
  }

  .cscene__row-label {
    font-size: 0.62rem;
  }

  .cscene__row-value,
  .cscene__row-greet {
    font-size: 0.66rem;
  }
}

@media (min-width: 48rem) {
  .cscene {
    --c-inset: 0.875rem;
    --c-gap: 0.75rem;
    --c-region-pad: 0.75rem;
    --c-row-h: 4rem;
    --c-result-h: 3.1rem;
    /* Panel apilado + cuatro filas a 4rem necesitan ~30rem de alto real
       (inset + panel + lista + resultado); el máximo heredado del tramo
       anterior (27.5rem) recortaba la primera fila con el panel activo
       en anchos de tablet (768-1023px), antes del salto a dos columnas
       de 64rem donde el panel deja de apilarse. */
    height: clamp(30rem, 58vh, 33rem);
  }

  /* Mismo selector (con el atributo) que la regla base que fija 6.6rem:
     una custom property la gana la especificidad, no el orden en la hoja,
     así que sobrescribirla solo en ".cscene" aquí nunca se habría
     aplicado por debajo de esta anchura. */
  .cscene[data-panel="catalog"],
  .cscene[data-panel="docs"] {
    --c-panel-h: 7.4rem;
  }

  .cscene__panel-title,
  .cscene__cat-name,
  .cscene__cat-address,
  .cscene__chip {
    font-size: 0.68rem;
  }

  .cscene__result-text {
    font-size: 0.8rem;
  }

  .cscene__result-meta {
    font-size: 0.66rem;
  }
}

/* Desktop: mismo apilado vertical que mobile (panel arriba, filas debajo,
   resultado al fondo) — SIN columna lateral. Juan probó la versión de dos
   columnas y no la quiso para Correos: angostaba el panel, obligaba a
   tipografía diminuta y hacía que la escena se sintiera más técnica que
   mobile, justo lo contrario de lo que el sitio busca. La base de datos y
   los documentos pasan a un panel HORIZONTAL A TODO EL ANCHO — mismo
   principio que Facturas/Soportes/Pagos, que tampoco reservan una columna
   fija para su canvas. Por id, mismo motivo que Soportes/Pagos:
   [data-scene-canvas] es compartido y esa regla no debe tocarse. */
#scene-correos,
#scene-emails,
#scene-courriels {
  display: block;
}

@media (min-width: 64rem) {
  .cscene {
    /* Más ancho que Soportes (44rem) y Pagos (38rem) a propósito: un panel
       horizontal de 4 tarjetas o 8 referencias necesita más aire que una
       lista de texto para no volver a sentirse angosto. */
    max-width: 58rem;
    margin: var(--space-5) auto 0;
    /* Con las tres hermanas OCULTAS (no comprimidas) en la etapa 5, ya no
       es el correo ampliado quien fija el mínimo — es la etapa 2/3, con el
       panel horizontal de dos filas + las cuatro filas completas +
       resultado. */
    height: clamp(33rem, 46vh, 35rem);
  }

  /* El panel horizontal necesita su propia altura por tramo: ~2 filas de
     tarjetas en Base de datos, o una sola fila de referencias en
     Documentos — comparten variable, así que se dimensiona para la vista
     más alta y la más corta queda centrada dentro (ver
     [data-panel-view] más abajo). */
  .cscene[data-panel="catalog"],
  .cscene[data-panel="docs"] {
    --c-panel-h: 8.4rem;
  }

  .cscene__panel-view {
    justify-content: center;
  }

  .cscene__panel-title {
    font-size: 0.74rem;
  }

  /* --- Base de datos: de lista vertical enmascarada a tarjetas en rejilla.
     Mismo HTML que mobile (coincidencias y relleno intercalados) — el
     orden visual se resuelve por CSS (order), sin tocar el DOM ni el
     recorrido de mobile. */
  .cscene__cat-list {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.6rem;
    align-content: center;
    -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
  }

  .cscene__cat-row {
    order: 1;
    height: auto;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0.2rem;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-small);
    background: var(--bg);
  }

  /* Las cuatro coincidencias siempre en la primera fila de la rejilla; el
     relleno ocupa la segunda — es lo único que decide su orden en pantalla. */
  .cscene__cat-row--match {
    order: 0;
  }

  .cscene__cat-row--filler {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    background: var(--surface);
    opacity: 1;
  }

  .cscene__cat-row--filler::before,
  .cscene__cat-row--filler::after {
    content: '';
    display: block;
    height: 0.45rem;
    border-radius: 999px;
    background: var(--line);
  }

  .cscene__cat-row--filler::after {
    width: 65%;
  }

  .cscene__cat-name,
  .cscene__cat-address {
    font-size: 0.72rem;
    white-space: normal;
  }

  .cscene__cat-address {
    font-size: 0.68rem;
  }

  /* --- Documentos: las ocho referencias en una sola fila ------------------ */
  .cscene__chip-grid {
    grid-template-columns: repeat(8, 1fr);
    align-content: center;
  }

  .cscene__chip {
    padding: 0.4rem 0;
    font-size: 0.68rem;
  }

  .cscene__row {
    padding: 0.9rem 0.75rem 0.35rem;
  }

  .cscene__row-name {
    font-size: 0.8rem;
  }

  .cscene__row-label {
    font-size: 0.68rem;
  }

  .cscene__row-value,
  .cscene__row-greet {
    font-size: 0.72rem;
  }

  .cscene__expanded-brand {
    font-size: 0.76rem;
  }

  .cscene__expanded-body,
  .cscene__expanded-sign {
    font-size: 0.72rem;
  }

  .cscene__attach-name {
    font-size: 0.7rem;
  }

  .cscene__attach-file {
    font-size: 0.66rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cscene__flip {
    transition: none;
  }

  .cscene__row {
    transition: opacity 0.2s ease, border-color 0.2s ease;
  }

  .cscene__row.is-sending {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   Chrome de las escenas con canvas (Facturas, Soportes, Pagos y Correos) —
   compactado para que el COMPONENTE INTERACTIVO COMPLETO (cabecera +
   rótulo + progreso + canvas + controles) quepa en 390x844 sin scroll.
   Todo scopeado a [data-scene-canvas].
   -------------------------------------------------------------------------- */

.scene[data-scene-canvas] .scene__heading {
  padding: var(--space-3) var(--space-3) 0;
  gap: 0.3rem;
}

/* Una sola línea meta («Recorrido visual · 20 s») en vez de eyebrow arriba
   y duración abajo: ahorra ~28px sin perder ninguna de las dos cosas. */
.scene[data-scene-canvas] .scene__heading h3 {
  font-size: clamp(1.05rem, 3.6vw, 1.5rem);
  line-height: 1.25;
  max-width: 34ch;
}

.scene[data-scene-canvas] .scene__stage-label {
  padding: var(--space-2) var(--space-3) 0;
  font-size: 0.875rem;
  line-height: 1.45;
  min-height: 2.6rem;
}

.scene[data-scene-canvas] .scene-progress {
  padding: 0.35rem var(--space-3) 0;
}

.scene[data-scene-canvas] .scene__controls {
  padding: var(--space-3);
}

.scene[data-scene-canvas] .text-alternative {
  padding: var(--space-2) var(--space-3);
}

/* Desktop: copy/progreso/controles a un lado y el canvas al otro, como
   V1.3 — el canvas gana ancho real y la sección la fija el canvas, no el
   texto. Misma composición interna que mobile, solo más holgada. */
@media (min-width: 64rem) {
  .scene[data-scene-canvas] {
    display: grid;
    grid-template-columns: minmax(15rem, 21rem) minmax(0, 1fr);
    grid-template-areas:
      "heading  canvas"
      "label    canvas"
      "progress canvas"
      "controls canvas"
      "alt      canvas";
    grid-template-rows: auto auto auto auto 1fr;
    align-items: start;
    gap: 0 var(--space-5);
    padding: var(--space-4);
  }

  .scene[data-scene-canvas] .scene__heading {
    grid-area: heading;
    padding: 0;
  }

  .scene[data-scene-canvas] .scene__stage-label {
    grid-area: label;
    padding: var(--space-4) 0 0;
  }

  .scene[data-scene-canvas] .scene-progress {
    grid-area: progress;
    padding: var(--space-2) 0 0;
  }

  .scene[data-scene-canvas] .iscene,
  .scene[data-scene-canvas] .sscene,
  .scene[data-scene-canvas] .pscene,
  .scene[data-scene-canvas] .cscene {
    grid-area: canvas;
  }

  .scene[data-scene-canvas] .scene__controls {
    grid-area: controls;
    padding: var(--space-4) 0 0;
  }

  .scene[data-scene-canvas] .text-alternative {
    grid-area: alt;
    align-self: start;
    margin-top: var(--space-4);
    padding: 0;
  }
}

.case-outro {
  display: grid;
  gap: var(--space-4);
}

.case-conclusion {
  font-size: clamp(1.05rem, 3.4vw, 1.25rem);
  font-weight: 600;
  line-height: 1.5;
  max-width: var(--reading);
}

.case-outro__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
}

.case-next {
  min-height: 2.75rem;
  padding: 0.7rem 1.1rem;
  background: var(--ink);
  color: var(--bg);
  border: 0;
  border-radius: var(--radius-small);
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.case-close-link {
  min-height: 2.75rem;
  padding: 0.5rem 0;
  background: none;
  border: 0;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--ink-secondary);
  cursor: pointer;
}

@media (min-width: 48rem) {
  .detail-grid {
    grid-template-columns: 1fr 1fr;
  }

  .case-outro {
    grid-template-columns: 1fr auto;
    align-items: center;
  }
}

/* ==========================================================================
   Capítulo humano: video + fuera del trabajo + contacto, un solo capítulo
   continuo. #video, #fuera-del-trabajo y #contacto se conservan como
   puntos de anclaje internos (navegación/accesibilidad), pero visualmente
   no hay salto entre ellos — .personal-note usa display:contents para que
   su copy y su foto se integren directamente en el grid del capítulo.
   ========================================================================== */

.personal-chapter {
  padding-block: var(--space-7);
  display: grid;
  gap: var(--space-6);
}

.personal-video,
.personal-note__copy,
.photo-slot,
.contact-block {
  min-width: 0;
}

.personal-video {
  display: grid;
  gap: var(--space-3);
}

.video-slot {
  aspect-ratio: 16 / 9;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}

.video-slot__media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

.personal-note {
  display: contents;
}

.personal-note__copy {
  display: grid;
  gap: var(--space-2);
  max-width: var(--reading);
}

.personal-note__copy h3 {
  font-size: clamp(1.4rem, 5vw, 2rem);
  font-weight: 800;
}

.personal-note__copy p {
  color: var(--ink-secondary);
  line-height: 1.6;
}

/* Fotografía de cierre: horizontal (sesión / hablar en público), a
   propósito distinta del retrato vertical del hero. */
.photo-slot {
  aspect-ratio: 3 / 2;
  width: min(100%, 30rem);
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.photo-slot__picture {
  display: block;
  width: 100%;
  height: 100%;
}

.photo-slot__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.contact-block {
  display: grid;
  gap: var(--space-4);
}

.contact-block h2 {
  font-size: clamp(1.6rem, 5.5vw, 2.4rem);
  font-weight: 800;
}

.contact-block p {
  color: var(--ink-secondary);
  max-width: var(--reading);
  line-height: 1.6;
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  border-top: 1px solid var(--ink);
  padding-top: var(--space-3);
}

.contact-link,
.contact-actions button {
  flex: 1 1 8rem;
  min-height: 3.25rem;
  padding-inline: 1.25rem;
  border: 1px solid var(--ink);
  background: transparent;
  border-radius: var(--radius-small);
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
  color: var(--ink);
}

/* CV — tercera acción neutra: mismo gris de superficie que el resto del
   sitio, ni verde ni azul, para que se distinga sin sumar una marca propia.
   Selector doble porque el CTA puede ser <a> (idioma con PDF activo) o
   <button disabled> (idioma todavía sin PDF), con el mismo tratamiento. */
.contact-actions button,
.contact-link--cv {
  background: var(--surface);
}

.contact-link--cv:hover {
  background: #ececef;
}

.contact-actions button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* WhatsApp y LinkedIn — mismo peso visual entre sí: mismo borde, mismo
   padding, misma tipografía, solo un tinte extremadamente suave que apenas
   referencia cada marca. Nada de verde/azul corporativo saturado. */
.contact-link--primary {
  background: #f2f8f4;
  border-color: #d6ead9;
}

.contact-link--primary:hover {
  background: #e9f4ec;
  border-color: #c7e0cc;
}

.contact-link--secondary {
  background: #f2f6fa;
  border-color: #d6e3ee;
}

.contact-link--secondary:hover {
  background: #e8f0f8;
  border-color: #c4d7e8;
}

.contact-link:active,
.contact-actions button:active {
  transform: translateY(1px);
}

@media (min-width: 48rem) {
  .personal-chapter {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "video   video"
      "note    photo"
      "contact photo";
    row-gap: var(--space-5);
  }

  .personal-video {
    grid-area: video;
  }

  .personal-note__copy {
    grid-area: note;
  }

  .photo-slot {
    grid-area: photo;
  }

  .contact-block {
    grid-area: contact;
  }
}

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--space-5);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: 0.85rem;
  color: var(--ink-secondary);
}

.site-footer a {
  text-decoration: none;
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
}

.site-footer a:hover {
  color: var(--ink);
}

/* ==========================================================================
   Ancho editorial en pantallas muy grandes
   ========================================================================== */

@media (min-width: 90rem) {
  .wrap {
    padding-inline: max(var(--pad), calc((100% - 90rem) / 2 + 2rem));
  }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
