/* ============================================================================
   scalebatch — el CHROME del sitio: barra, controles, pie, y las reglas que
   valen para todas las paginas. Lo especifico de cada pagina se queda en ella.

   Se carga DESPUES de tokens.css, que es el dueno de la paleta.

   Modelo: `products/buildsigned/web/css/site.css` y el de matchitfy, tomando
   de cada uno lo que el otro tiene mal. Esta escrito abajo caso por caso, y
   no como adorno: los dos productos estan en produccion con esos defectos y
   sin la nota alguien los copia otra vez.
   ============================================================================ */

@layer reset, base, chrome;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; }
  img, svg { max-width: 100%; }
  img { display: block; }

  /* DE BUILDSIGNED, Y MATCHITFY NO LO TIENE. Sin esto, una pagina que crece y
     estrena barra de scroll mete un salto horizontal de 15px. matchitfy lo
     compensa con `body{overflow-x:hidden}`, que es exactamente lo que
     WEB_PATTERNS §6 llama esconder el bug: la barra desaparece y con ella la
     unica senal de que algo desborda. Una linea, y va desde el principio. */
  html { scrollbar-gutter: stable; }
}

@layer base {
  html { -webkit-text-size-adjust: 100%; background: var(--ground); }

  /* GUARD DE IDIOMA CON FAILSAFE DE CSS PURO.
     `WEB_PATTERNS` §2.1 describe un guard que oculta el body con `data-fouc` y
     lo revela con `revealBody()`. Eso no existe en ningun producto del taller y
     aqui tampoco: es la desviacion 1 del CLAUDE.md de este producto.

     Lo que hay es mas estrecho y suficiente. El ingles vive en el HTML, asi que
     en ingles NO SE OCULTA NADA. Solo el espanol espera al diccionario, y la
     animacion de 0s con 1,5s de retraso lo revela SOLO aunque i18n.js no llegue
     nunca. Un diccionario que no carga deja la pagina en ingles, jamas en
     blanco. */
  .i18n-wait body {
    visibility: hidden;
    animation: i18n-failsafe 0s linear 1.5s forwards;
  }
  @keyframes i18n-failsafe { to { visibility: visible; } }

  body {
    background: var(--ground);
    color: var(--ink);
    font-family: var(--font-sans);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
  }

  .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

  /* El riel. Ancho maximo del contenido y respiracion lateral.
     `.rail` es el mismo nombre que ya usa el landing; se aceptan los dos para
     no reescribir cuarenta apariciones, y `.wrap` es el que usan buildsigned y
     matchitfy, asi que una pagina copiada de cualquiera de los dos encaja. */
  .wrap, .rail {
    width: min(var(--sb-content-max), calc(100% - 2 * var(--sb-page-gutter)));
    margin-inline: auto;
  }

  /* DE MATCHITFY: transiciones de vista NATIVAS entre paginas, cero JS.
     El sitio son paginas separadas con `<a href>` normal, no un SPA. El
     pestaneo entre paginas se mata aqui y en los navegadores que no lo soportan
     simplemente no hace nada. Es la respuesta correcta a "SPA sin flickering"
     para un sitio de marketing: htmx en un landing de siete paginas paga el
     costo de un shell y no compra nada. */
  @view-transition { navigation: auto; }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
    }
    /* EL RESET DE MOVIMIENTO NO PUEDE TOCAR EL FAILSAFE. Poner su duracion en
       0.01ms lo dispararia de inmediato y reintroduciria el destello que el
       guard existe para evitar. Se le devuelve su 0s explicito. */
    .i18n-wait body { animation-duration: 0s !important; }
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
      animation: none !important;
    }
  }

  /* Enlace de salto: lo primero que recibe foco con el teclado. */
  .skip {
    position: absolute; inset-inline-start: -9999px; inset-block-start: 0;
    z-index: 100;
    background: var(--paint); color: var(--on-paint);
    padding: .75rem 1.1rem; font-weight: 800; font-size: .8125rem;
    text-decoration: none;
  }
  .skip:focus { inset-inline-start: 0; }

  /* El foco visible alcanza a TODO control, no solo a los botones. */
  a:focus-visible, button:focus-visible, input:focus-visible,
  summary:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--paint);
    outline-offset: 2px;
  }
}

@layer chrome {

  /* ---------- barra superior ---------- */

  .top {
    position: sticky; top: 0; z-index: 50;
    /* OPACO, no translucido. A .94 y sin `backdrop-filter` se colaban ocho
       niveles del contenido de abajo y se percibia como parpadeo al pasar por
       encima de las cabeceras de calle. */
    background: var(--ground);
    border-bottom: 1px solid var(--line);
  }
  /* LOS DOS NOMBRES, y el que faltaba costo la primera captura: `site.css`
     estilizaba `.top .wrap` y el marcado del landing decia `.rail`, asi que el
     `display:flex` no aplico nunca y la barra se partio en tres filas. El CSS
     era correcto y el selector no encontraba a nadie, que es el fallo que
     ningun `nginx -t` ni ningun grep de tokens detecta: solo se ve midiendo el
     DOM pintado. */
  .top .wrap, .top .rail {
    display: flex; align-items: center; gap: 1rem;
    min-height: 64px; flex-wrap: wrap;
  }

  .brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; color: inherit; }
  .brand svg { display: block; flex: none; }
  /* El nombre en dos tintas (MARCA.md §4). `--paint-ink` y no `--paint`: aqui
     el ambar es LETRA, y en tema claro el token de forma da 3.7:1 y no pasa.
     `lowercase` protege el nombre de un diccionario que lo capitalice. */
  .brand b {
    font-weight: 900; font-size: 1.1rem; letter-spacing: -.03em;
    text-transform: lowercase;
  }
  .brand b span { color: var(--paint-ink); }

  .top-nav {
    display: flex; align-items: center; gap: 1.1rem;
    margin-left: auto; flex-wrap: wrap;
  }
  .top-nav a {
    color: var(--concrete); text-decoration: none;
    font-size: .86rem; font-weight: 600;
    /* 44px, con `inline-flex` para que la altura la tome el AREA PULSABLE y no
       la caja de texto. matchitfy deja sus enlaces de barra en ~29px con
       `padding:4px 0`, que es descuido y no una excepcion razonada. */
    display: inline-flex; align-items: center; min-height: 44px;
    border-bottom: 2px solid transparent;
  }
  .top-nav a:hover { color: var(--ink); }

  /* LA REGLA DE `aria-current` SE ESCRIBE EL MISMO DIA QUE EL ATRIBUTO.
     buildsigned pone el atributo en seis paginas y su site.css no lo estiliza:
     `grep aria-current css/site.css` da CERO. La pagina activa no se marca en
     todo su landing. Es el bug 1 de la tabla del CLAUDE.md de este producto y
     no entra aqui. */
  .top-nav a[aria-current="page"] {
    color: var(--ink);
    border-bottom-color: var(--paint);
  }

  /* ---------- controles de preferencia: 28px, a proposito ----------
     `WEB_PATTERNS` §6 pide 44px en todo control y esta es la desviacion 2 del
     CLAUDE.md de este producto, copiada de los dos modelos porque los dos la
     midieron: al tamano de un boton de accion competian visualmente con el
     acceso, y ademas EMPUJABAN LA BARRA al cambiar de idioma, porque el rotulo
     mide distinto en cada idioma. 28px queda por encima del minimo de 24px que
     pide WCAG 2.2 para objetivo tactil.

     LA EXCEPCION ES SOLO PARA `.seg button`. Todo lo demas mantiene los 44px,
     incluidos los enlaces del pie. */
  .top-ctl { display: flex; align-items: center; gap: .6rem; }

  .seg { display: inline-flex; border: 1px solid var(--line); overflow: hidden; }
  .seg button {
    font: inherit; font-size: .72rem; font-weight: 800; letter-spacing: .06em;
    padding: .25rem .5rem; min-height: 28px; cursor: pointer;
    border: 0; background: none; color: var(--concrete);
    display: inline-flex; align-items: center; justify-content: center;
  }
  .seg button + button { border-inline-start: 1px solid var(--line); }
  .seg button:hover { color: var(--ink); }
  .seg button[aria-pressed="true"] { background: var(--ink); color: var(--ground); }

  .theme-btn { display: inline-flex; align-items: center; justify-content: center; }
  .theme-btn .ico { display: block; flex: none; }
  .theme-btn[data-theme-state="dark"]  .ico-moon { display: none; }
  .theme-btn[data-theme-state="light"] .ico-sun  { display: none; }
  /* Antes de que corra el JS no hay estado estampado. El sitio nace OSCURO
     (`color-scheme: dark` en tokens.css), asi que lo correcto en esa ventana es
     ensenar el sol, que es la accion disponible. buildsigned ensena la luna
     aqui porque el suyo nace claro; copiarlo tal cual habria dejado el icono
     equivocado durante el arranque. */
  .theme-btn:not([data-theme-state]) .ico-moon { display: none; }

  /* ---------- botones ---------- */

  .btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; padding: .7rem 1.2rem;
    font-weight: 800; font-size: .95rem; text-decoration: none;
    border: 1px solid var(--paint); background: var(--paint); color: var(--on-paint);
    cursor: pointer;
  }
  .btn:hover { filter: brightness(1.08); }
  .btn-ghost { background: transparent; color: var(--ink); border-color: var(--line); }
  .btn-ghost:hover { border-color: var(--ink); filter: none; }

  /* ---------- pie ---------- */

  .foot {
    border-top: 1px solid var(--line);
    background: var(--ground-2);
    color: var(--concrete);
  }
  .foot-grid {
    display: grid;
    /* `minmax(min(150px,100%),1fr)` y no `minmax(150px,1fr)`: un track con
       minimo fijo mas ancho que el contenedor no se encoge, desborda, y el
       desbordamiento sale por el documento entero. Medido en matchitfy:
       400px de scrollWidth contra 390 de viewport. */
    grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(min(140px, 100%), 1fr));
    gap: 1.6rem clamp(1rem, 3vw, 2.5rem);
    padding-block: 2.6rem 1.8rem;
  }
  .foot-col h2 {
    font-size: .78rem; font-weight: 800; letter-spacing: .11em;
    text-transform: uppercase; color: var(--concrete-dim);
    margin: 0 0 .5rem;
  }
  .foot-col ul { list-style: none; margin: 0; padding: 0; }
  /* 44px TAMBIEN AQUI, con `inline-flex`. Es donde matchitfy los pierde: sus
     enlaces de pie son inline a 14px x 1.5, o sea 21px de area pulsable, sin
     `display`, sin `min-height` y sin padding vertical. Sin el `inline-flex` un
     `min-height` sobre un inline no hace absolutamente nada, y ese es el
     detalle que hace que el bug parezca arreglado cuando no lo esta. */
  .foot-col a {
    color: var(--ink); text-decoration: none;
    font-size: .92rem; font-weight: 600;
    display: inline-flex; align-items: center; min-height: 44px;
  }
  .foot-col a:hover { text-decoration: underline; text-underline-offset: 3px; }
  .foot-col .tag { font-size: .92rem; color: var(--concrete); max-width: 34ch; margin: .6rem 0 0; }

  .foot-bottom {
    display: flex; justify-content: space-between; gap: .6rem 1.5rem; flex-wrap: wrap;
    border-top: 1px solid var(--line);
    padding-block: 1.1rem 2.2rem;
    font-size: .8125rem; color: var(--concrete-dim);
  }

  /* ---------- angosto ---------- */

  @media (max-width: 56rem) {
    .foot-grid { grid-template-columns: repeat(2, minmax(min(150px, 100%), 1fr)); }
  }

  @media (max-width: 900px) {
    /* La barra NO desaparece: se reordena. El menu baja a su propia fila y
       scrollea en horizontal si hace falta, con una mascara que avisa de que
       hay mas a la derecha. Los controles se quedan arriba con la marca. */
    .top-nav {
      order: 3; width: 100%; margin-left: 0; gap: .9rem;
      flex-wrap: nowrap; overflow-x: auto;
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
      -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
      mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    }
    .top-nav::-webkit-scrollbar { display: none; }
    .top-nav a { white-space: nowrap; }
    .top-ctl { margin-left: auto; }
  }
}

/* ============================================================================
   OBJETOS DE CONTENIDO. Los cinco que se repiten en todas las paginas.

   Salen del barrido de buildsigned pagina por pagina (2026-08-23). Lo que hace
   que ese sitio no sea un muro de texto no son catorce disenos: son CINCO
   objetos reutilizados, y cada uno responde a una forma distinta de pregunta.

     .sheet + .stat-table   "aqui esta el numero, y de donde salio"
     .triggers              "aqui estan los N casos"
     .roles / .role.no      "y esto es lo que NO"
     .figures               "la prueba es una cifra"
     .cta-close             el cierre que remata EL argumento de esa pagina

   Tener cinco y no quince es lo que hace que una pagina nueva se escriba en una
   tarde: se elige el objeto por la forma de la respuesta, no se inventa layout.
   ============================================================================ */

@layer chrome {

  /* ---------- el esqueleto de una pagina ---------- */

  /* Apertura de TODA pagina interior: tres elementos y punto.
     eyebrow (categoria) -> h1 -> lede. Nada mas. El hero de la portada es el
     unico que agrega algo, y lo que agrega no es tipografia mas grande sino
     contexto: el configurador al lado. */
  .eyebrow {
    display: block; font-family: var(--font-mono);
    font-size: .8125rem; font-weight: 700; letter-spacing: .11em;
    text-transform: uppercase; color: var(--paint-ink);
    margin-bottom: .9rem;
  }

  .sec { padding-block: clamp(2.8rem, 7vw, 5rem); }
  /* Alternancia de superficie. Es lo unico que separa una seccion de la
     siguiente: sin lineas divisorias, que a esta densidad son ruido. */
  .sec.alt { background: var(--ground-2); }

  .sec h2 { margin: 0 0 .5rem; font-size: clamp(1.35rem, 2.4vw, 2rem); font-weight: 900; letter-spacing: -.02em; line-height: 1.1; }
  .sec h3 { margin: 0 0 .35rem; font-size: 1.05rem; font-weight: 800; letter-spacing: -.01em; }
  .sec .lede { max-width: 68ch; color: var(--concrete); font-size: 1.02rem; margin: 0 0 1.6rem; }
  .sec p { margin: 0 0 .9rem; }
  .sec p:last-child { margin-bottom: 0; }

  /* El hero de una pagina interior. Mismo h1 que la portada: lo que cambia es
     que aqui no hay nada al lado. */
  .page-hero { padding-block: clamp(2.6rem, 6vw, 4.4rem) clamp(1.6rem, 3vw, 2.4rem); }
  .page-hero h1 { margin: 0; font-size: clamp(2.2rem, 5vw, 3.9rem); font-weight: 900; letter-spacing: -.03em; line-height: 1.02; text-wrap: balance; }
  .page-hero .lede { margin-top: 1rem; max-width: 64ch; color: var(--concrete); font-size: clamp(1rem, 1.4vw, 1.12rem); }

  /* Dos columnas: el argumento a la izquierda, el objeto a la derecha. */
  .split { display: grid; gap: clamp(1.2rem, 3vw, 2.4rem); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
  @media (max-width: 60rem) { .split { grid-template-columns: minmax(0, 1fr); } }

  /* ---------- 1. la hoja con su tabla ---------- */

  /* LA TERCERA COLUMNA ES EL ARGUMENTO. En buildsigned la tabla del asiento
     lleva Item / Value / Source, y cada cifra dice de donde salio: del
     contrato, de un estatuto citado por numero, o calculada. Ninguna dice
     "confia". Aqui la tercera columna es el ORIGEN del apunte: que deposito,
     que fase, que lote. */
  .sheet {
    background: var(--ground-2); border: 1px solid var(--line);
    padding: 1.1rem 1.2rem;
  }
  .sheet h3 { font-family: var(--font-mono); font-size: .8125rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--concrete-dim); margin-bottom: .8rem; }
  .stat-table { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: .875rem; font-variant-numeric: tabular-nums; }
  .stat-table th { text-align: left; font-size: .72rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--concrete-dim); padding: 0 .6rem .5rem 0; border-bottom: 1px solid var(--line); }
  .stat-table td { padding: .45rem .6rem .45rem 0; border-bottom: 1px solid var(--line); vertical-align: top; }
  .stat-table td:nth-child(2) { text-align: right; white-space: nowrap; }
  .stat-table td:last-child { color: var(--concrete-dim); font-size: .78rem; }
  /* El unico enfasis de la tabla. Si hay dos, no hay ninguno. */
  .stat-table tr.total td { border-bottom: 0; border-top: 2px solid var(--paint); font-weight: 700; color: var(--ink); padding-top: .6rem; }

  /* ---------- 2. la lista de casos ---------- */

  .triggers { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
  .triggers li { display: grid; gap: .15rem; padding: .8rem 0; border-bottom: 1px solid var(--line); }
  .triggers li:last-child { border-bottom: 0; }
  .triggers .t { font-weight: 800; font-size: 1rem; }
  .triggers .d { color: var(--concrete); font-size: .9rem; }

  /* ---------- 3. las tarjetas, y las que niegan ---------- */

  .roles { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }
  .role { background: var(--ground-2); border: 1px solid var(--line); padding: 1rem 1.1rem; }
  .role p { color: var(--concrete); font-size: .94rem; margin: 0; }
  /* LA REGLA EDITORIAL DEL SITIO MODELO, y es la que mas cuesta copiar porque
     no es CSS: cada pagina tiene una seccion sobre lo que el producto NO hace,
     escrita con mas precision que las que dicen lo que si. `.role.no` es como
     se marca. El borde ambar de la izquierda es el mismo del resto del sistema;
     lo que cambia es que aqui significa "lee esto dos veces". */
  .role.no { border-left: 3px solid var(--paint); }
  .role.no h3 { color: var(--paint-ink); }

  /* ---------- 4. la cifra como prueba ---------- */

  .figures { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr)); }
  .figures .n { display: block; font-family: var(--font-mono); font-size: clamp(1.9rem, 4.4vw, 2.8rem); font-weight: 700; letter-spacing: -.03em; line-height: 1; color: var(--ink); }
  .figures .k { display: block; margin-top: .4rem; color: var(--concrete); font-size: .9rem; max-width: 30ch; }
  .figures .src { display: block; margin-top: .3rem; font-family: var(--font-mono); font-size: .72rem; color: var(--concrete-dim); }

  /* ---------- 5. el cierre ---------- */

  /* EL h2 DEL CIERRE REMATA EL ARGUMENTO DE ESA PAGINA, no dice "Regístrate".
     Y el boton fantasma apunta a la SIGUIENTE pregunta del recorrido, no a la
     portada: el recorrido esta cableado en esos botones y es un ciclo cerrado,
     asi que nadie llega a un callejon.
     En buildsigned `.cta-close` no tiene una sola regla CSS y funciona por
     accidente heredando de `.sec`. Aqui se declara. */
  .cta-close { background: var(--ground-2); border-top: 1px solid var(--line); }
  .cta-close h2 { max-width: 24ch; }
  .cta-close .lede { margin-bottom: 1.4rem; }
  .cta-row { display: flex; flex-wrap: wrap; gap: .7rem; }
}

/* ============================================================================
   EL MOLDE DE LAS LEGALES. Otro entero, y a proposito.

   Los dos modelos del taller hacen lo mismo: sus paginas legales no usan las
   secciones alternas, ni los objetos de contenido, ni el cierre con CTA. Son
   una sola columna estrecha de prosa. La razon es que el trabajo de la pagina
   es distinto: aqui nadie viene a decidir una compra, viene a comprobar algo
   concreto, y toda pieza de venta que se le cruce estorba.

   `74ch` es el ancho de matchitfy y esta bien medido: por encima de ~80 la
   linea es dificil de seguir de vuelta al margen.
   ============================================================================ */

@layer chrome {

  /* ALINEADA A LA IZQUIERDA DEL RIEL, no centrada. `.doc` iba sobre el mismo
     elemento que `.rail` y heredaba su `margin-inline:auto`, asi que la columna
     de 74ch se centraba en los 78rem del riel y el texto arrancaba 240px a la
     derecha del titular. Un documento cuyo primer parrafo no empieza donde
     empieza su titulo se lee como si fuera otra pagina. */
  .doc { max-width: 74ch; margin-inline: 0; padding-block: clamp(1.5rem, 4vw, 2.5rem) clamp(3rem, 8vw, 5rem); }

  /* El h2 lleva linea arriba en vez de fondo alterno: en un documento largo la
     alternancia de superficie se lee como si cambiara el tema, y aqui todo es
     el mismo tema. */
  .doc h2 {
    margin: 2.2rem 0 .6rem; padding-top: 1.4rem;
    border-top: 1px solid var(--line);
    font-size: 1.3rem; font-weight: 800; letter-spacing: -.015em; line-height: 1.2;
  }
  .doc h2:first-of-type { margin-top: .6rem; }
  .doc h3 { margin: 1.4rem 0 .4rem; font-size: 1.05rem; font-weight: 800; }
  .doc p { margin: 0 0 .9rem; font-size: 1rem; line-height: 1.65; color: var(--concrete); }
  .doc p strong { color: var(--ink); font-weight: 700; }
  .doc ul { margin: 0 0 1rem; padding-left: 1.1rem; }
  .doc li { margin-bottom: .45rem; font-size: 1rem; line-height: 1.6; color: var(--concrete); }
  .doc a { color: var(--paint-ink); }

  /* La tabla de subencargados. Estrecha, sin la hoja: no es una cifra que
     probar, es una lista que comprobar. */
  .doc table { width: 100%; border-collapse: collapse; margin: 0 0 1.2rem; font-size: .92rem; }
  .doc th { text-align: left; font-family: var(--font-mono); font-size: .72rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--concrete-dim); padding: 0 .8rem .5rem 0; border-bottom: 1px solid var(--line); }
  .doc td { padding: .55rem .8rem .55rem 0; border-bottom: 1px solid var(--line); color: var(--concrete); vertical-align: top; }
  .doc td:first-child { color: var(--ink); font-weight: 700; white-space: nowrap; }
}
