/* ═══════════════════════════════════════════════════════════════════════════
   tokens.css — sistema de diseño INEFAM

   DECISIÓN DE TEMA (19-ago-2026)
   El sitio es CLARO por defecto, en los dos sentidos: es el tema que se sirve
   sin preguntar al sistema operativo, y es el tema para el que está diseñado.
   La razón está medida: #711D1D da 11:1 sobre papel blanco —o sea sirve como
   color de TEXTO— y 1.77:1 sobre negro, donde no puede portar ni una letra.
   Una marca de un solo matiz rinde el doble en claro.

   El tema oscuro existe, es completo y se elige con el conmutador del
   encabezado. NO se hereda de `prefers-color-scheme`: un sitio institucional
   se presenta como decidió su dueño, no como quedó configurada la laptop del
   visitante. La preferencia elegida se recuerda en localStorage.

   EL ERROR QUE ESTO CORRIGE
   El ritmo de secciones estaba escrito con --bg / --superficie / --superficie-2,
   que en claro son blanco, hueso y crema —tres papeles distinguibles— pero en
   oscuro caían a #1A1413, #221A18 y #2C2220: 6% de luminancia entre ellos.
   Siete secciones distintas se veían como una sola mancha negra. Ahora cada
   sección tiene su propio token de superficie, y en oscuro la sección "tinta"
   se resuelve con un negro AGUINDADO: separa por matiz, no por luminancia,
   que es lo único que funciona cuando todo el rango vive en el 10% inferior.

   INVARIANTE QUE NO CAMBIA:
   #711D1D sobre fondo oscuro da 1.77:1 — no puede portar texto. En oscuro el
   acento es un tinte claro de la rampa; el guinda puro sólo como relleno.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── ÚNICA diferencia contra `web/src/styles/tokens.css` ──────────────────
   El sitio público resuelve los paquetes de @fontsource con el empaquetador
   de Astro. El portal se sirve como CSS plano desde FastAPI, donde
   `@import "@fontsource/..."` no significa nada. Los mismos archivos .woff2
   están copiados en `fuentes/` y `fuentes.css` los declara.
   El resto del archivo es idéntico, a propósito: el cliente tiene que sentir
   un solo INEFAM entre inefam.com y el portal. Cuando cambie el original,
   se vuelve a copiar y se vuelve a aplicar sólo este bloque.
   ───────────────────────────────────────────────────────────────────────── */
@import "./fuentes.css";

:root {
  /* ── Rampa de marca, con ROL asignado ───────────────────────────────────
     Advertencia: los pasos 300-500 son coral. En superficies grandes
     convierten el guinda serio en rosa de startup. Sólo texto sobre oscuro,
     acentos puntuales y series de datos.                                    */
  --brand-50:  #FEF5F3;  /* fondo de sección clara alterna */
  --brand-100: #FEE6E3;  /* superficie de tarjeta sobre el 50, insignias */
  --brand-200: #FECCC6;  /* bordes decorativos, relleno de gráfica bajo */
  --brand-300: #FEA7A0;  /* SOLO texto/icono sobre oscuro */
  --brand-400: #EB837B;  /* acento vivo sobre oscuro */
  --brand-500: #D4605A;  /* hover de acento sobre oscuro, series */
  --brand-600: #AF4642;  /* hover de botón sobre claro, series */
  --brand-700: #8C3230;  /* bordes activos, estado presionado */
  --brand-800: #711D1D;  /* MARCA. Encabezado, banda, botón primario */
  --brand-900: #521312;  /* banda oscura guinda, sombras teñidas */
  --brand-950: #3C0708;  /* tinta más profunda */

  /* ── Neutros TINTADOS (matiz ~22°) ──────────────────────────────────────
     Nunca #F5F5F5 ni #888 ni #111: un gris puro junto al guinda se ve muerto. */
  --papel-0: #FFFFFF;
  --papel-1: #FBF8F6;
  --papel-2: #F5F0EC;
  --papel-3: #EDE6E1;

  --linea-1: #E5DBD5;
  --linea-2: #D2C5BC;

  --tinta-tenue: #7A6A63;
  --tinta-2:     #4A3D38;
  --tinta-1:     #241A17;
  --tinta-0:     #140D0C;   /* casi-negro CÁLIDO, no #000 */

  /* Superficies oscuras estratificadas */
  --oscuro-0: #120D0C;
  --oscuro-1: #191211;
  --oscuro-2: #221A18;
  --oscuro-3: #2C2220;

  /* Filetes sobre oscuro: derivados del acento, nunca blancos */
  --filete-osc-1: color-mix(in oklab, var(--brand-200) 10%, transparent);
  --filete-osc-2: color-mix(in oklab, var(--brand-200) 18%, transparent);

  /* ── Tipografía: tres voces ─────────────────────────────────────────────
     Serif editorial para display · grotesca para UI · monoespaciada para
     identificadores. La mono es el tercer registro que dice "inteligencia":
     un folio de licitación en mono vale más que tres iconos.
     Auto-hospedadas: un @import a Google expone la IP del visitante (LFPDPPP). */
  --f-display: "Instrument Serif", ui-serif, Georgia, serif;
  --f-ui: "Geist Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --f-mono: "Geist Mono Variable", ui-monospace, "Cascadia Mono", Consolas, monospace;

  --t-display: clamp(2.9rem, 5.6vw, 5.6rem);
  --t-h1:      clamp(2.2rem, 4vw, 3.75rem);
  --t-h2:      clamp(1.7rem, 2.6vw, 2.5rem);
  --t-h3:      clamp(1.15rem, 1.4vw, 1.45rem);
  --t-lg:      clamp(1.06rem, 1.15vw, 1.2rem);
  --t-base:    1rem;
  --t-sm:      0.875rem;
  --t-xs:      0.75rem;

  /* ── Anchos: el truco más barato para producir ritmo ─────────────────── */
  --w-completo: 100%;
  --w-ancho: 84rem;    /* visualizaciones, tablas, franjas de datos */
  --w-base:  72rem;    /* rejillas, splits */
  --w-texto: 46rem;    /* prosa editorial */
  --w-angosto: 34rem;  /* citas, entradillas */

  /* ── Padding vertical ──────────────────────────────────────────────────
     Recalibrado a la baja. La versión anterior daba 12.5rem arriba y abajo a
     secciones con dos frases dentro: el aire sólo se sostiene cuando hay
     contenido que lo justifique, si no se lee como página sin terminar.     */
  --pad-xs: clamp(2.25rem, 3.2vw, 3rem);
  --pad-sm: clamp(3rem, 4.6vw, 4.5rem);
  --pad-md: clamp(4rem, 6vw, 6.5rem);
  --pad-lg: clamp(4.5rem, 7.5vw, 8.5rem);
  --pad-xl: clamp(5.5rem, 9vw, 10.5rem);

  --radio-sm: 4px; --radio: 10px; --radio-lg: 16px;

  /* ── Motion ──────────────────────────────────────────────────────────── */
  --e-salida:  cubic-bezier(0.16, 1, 0.3, 1);
  --e-cuarto:  cubic-bezier(0.25, 1, 0.5, 1);
  --e-inout:   cubic-bezier(0.76, 0, 0.24, 1);
  --d-micro:  140ms;
  --d-ui:     280ms;
  --d-revela: 820ms;

  /* ═══ TEMA CLARO — el canónico ═══════════════════════════════════════ */
  --bg: var(--papel-1);
  --superficie: var(--papel-0);
  --superficie-2: var(--papel-2);
  --superficie-3: var(--papel-3);
  --linea: var(--linea-1);
  --linea-fuerte: var(--linea-2);

  --texto: var(--tinta-1);
  --texto-2: var(--tinta-2);
  --texto-3: var(--tinta-tenue);

  --acento: var(--brand-800);       /* 11:1 sobre blanco: sirve como TEXTO */
  --acento-vivo: var(--brand-600);
  --campo: var(--brand-800);
  --campo-texto: #FFF6F4;

  /* ── Superficies POR SECCIÓN ────────────────────────────────────────────
     Cada una es un token propio para que el tema oscuro pueda separarlas por
     MATIZ y no sólo por luminancia. Sin esto el ritmo muere en oscuro.      */
  --sec-papel:  var(--papel-1);   /* hero, cita */
  --sec-blanco: var(--papel-0);   /* paneles, splits */
  --sec-crema:  var(--papel-2);   /* sección alterna */
  --sec-tinta:  var(--oscuro-0);  /* la sección oscura */
  --sec-campo:  var(--brand-800); /* franja a sangre */
  --sec-cierre: var(--brand-950); /* cierre */

  /* Tinta sobre superficies oscuras: se usa en tinta/campo/cierre en AMBOS
     temas, porque esas secciones son oscuras siempre. */
  --sobre-osc-1: #F6EDEA;
  --sobre-osc-2: rgba(246, 237, 234, 0.72);
  --sobre-osc-3: rgba(246, 237, 234, 0.48);
  --sobre-osc-linea: rgba(254, 204, 198, 0.15);
  --sobre-osc-acento: var(--brand-300);

  --sombra-hue: 6;
  --sombra: 0 1px 1px  hsl(var(--sombra-hue) 45% 22% / .05),
            0 2px 3px  hsl(var(--sombra-hue) 45% 22% / .05),
            0 8px 20px -8px hsl(var(--sombra-hue) 45% 22% / .10);

  /* Series de datos. La rampa de un matiz es SECUENCIAL, no categórica:
     sirve para magnitud. La identidad se resuelve con posición y etiqueta
     directa, nunca con color. Ver CLAUDE.md. */
  --serie-1: #711D1D;  --serie-2: #AF4642;
  --serie-3: #EB837B;  --serie-4: #FECCC6;
  --serie-tenue: #B9A9A1;

  color-scheme: light;
}

/* ═══ TEMA OSCURO — se ELIGE, no se hereda del sistema ══════════════════════
   Las superficies neutras suben un peldaño y la sección "tinta" se resuelve
   con negro aguindado: en el 10% inferior de luminancia el ojo ya no separa
   por claridad, sólo por matiz.                                             */
:root[data-tema="oscuro"] {
  --bg: var(--oscuro-1);
  --superficie: var(--oscuro-2);
  --superficie-2: var(--oscuro-3);
  --superficie-3: #362B28;
  --linea: var(--filete-osc-1);
  --linea-fuerte: var(--filete-osc-2);

  --texto: #F2E9E6;              /* nunca blanco puro sobre oscuro */
  --texto-2: rgba(242, 233, 230, 0.74);
  --texto-3: rgba(242, 233, 230, 0.52);

  --acento: var(--brand-300);    /* el guinda daría 1.77:1 */
  --acento-vivo: var(--brand-400);
  --campo: var(--brand-800);
  --campo-texto: #FFF6F4;

  --sec-papel:  #191211;
  --sec-blanco: #241B19;
  --sec-crema:  #13100F;
  --sec-tinta:  #2E0D0D;   /* negro AGUINDADO: separa por matiz */
  --sec-campo:  #711D1D;
  --sec-cierre: #4A1110;

  --sombra: 0 1px 2px rgba(0,0,0,.4), 0 12px 32px -12px rgba(20,8,8,.7);

  --serie-1: #D4605A;  --serie-2: #EB837B;
  --serie-3: #FEA7A0;  --serie-4: #FECCC6;
  --serie-tenue: #6E5C57;

  color-scheme: dark;
}

/* ═══ Reset ═══════════════════════════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  font-family: var(--f-ui);
  font-size: var(--t-base);
  line-height: 1.6;
  color: var(--texto);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-underline-offset: 0.2em; }
p { text-wrap: pretty; }

/* Tracking por tamaño. El tracking negativo en display es el 60% de la
   sensación "cara": sin él, cualquier grotesca a 6rem se ve suelta. */
h1, h2, h3, h4 { text-wrap: balance; font-weight: 500; }
.display { font-size: var(--t-display); letter-spacing: -0.035em; line-height: 0.95; }
h1, .h1 { font-size: var(--t-h1); letter-spacing: -0.028em; line-height: 1.02; }
h2, .h2 { font-size: var(--t-h2); letter-spacing: -0.02em; line-height: 1.08; }
h3, .h3 { font-size: var(--t-h3); letter-spacing: -0.012em; line-height: 1.25; }

.serif { font-family: var(--f-display); font-weight: 400; }
.mono {
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* Cero cortado: guiño de credibilidad de dato que casi nadie pone. */
.cifra, table, [data-num] {
  font-variant-numeric: tabular-nums slashed-zero lining-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
}

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

/* ═══ Anchos y utilidades ═════════════════════════════════════════════════ */
.ancho    { width: min(100% - 3rem, var(--w-ancho));   margin-inline: auto; }
.base     { width: min(100% - 3rem, var(--w-base));    margin-inline: auto; }
.texto    { width: min(100% - 3rem, var(--w-texto));   margin-inline: auto; }
.angosto  { width: min(100% - 3rem, var(--w-angosto)); margin-inline: auto; }
.contenedor { width: min(100% - 3rem, var(--w-base));  margin-inline: auto; }

/* Bloque que vive sobre una superficie oscura en los DOS temas. Reasigna los
   tokens de texto en cascada, de modo que cualquier componente anidado —una
   gráfica, un filete, una etiqueta— se adapta sin saber dónde está. */
.sobre-oscuro {
  --texto: var(--sobre-osc-1);
  --texto-2: var(--sobre-osc-2);
  --texto-3: var(--sobre-osc-3);
  --linea: var(--sobre-osc-linea);
  --linea-fuerte: rgba(254, 204, 198, 0.26);
  --acento: var(--sobre-osc-acento);
  --acento-vivo: var(--brand-400);
  --superficie: rgba(254, 204, 198, 0.045);
  --serie-1: #D4605A;  --serie-2: #EB837B;
  --serie-3: #FEA7A0;  --serie-4: #FECCC6;
  --serie-tenue: #6E5C57;
  color: var(--texto);
}

.solo-lectores {
  position: absolute; width: 1px; height: 1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ═══ Materiales ══════════════════════════════════════════════════════════
   Con un solo matiz, la variedad la dan los MATERIALES: papel granulado,
   vidrio esmerilado, panel oscuro con realce interno, tinta plana.
   Cuatro materiales, un color. ═════════════════════════════════════════════ */

/* Grano: convierte un guinda plano en tinta impresa y mata el banding. */
.grano { position: relative; isolation: isolate; }
.grano::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  opacity: .035; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
}

/* Tinte ambiental: no se lee como degradado, se lee como iluminación.
   Máximo 3 manchas, todas del mismo matiz, variando sólo luminancia. */
.atmosfera { position: relative; isolation: isolate; }
.atmosfera::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(80% 50% at 22% -6%,  rgba(174,60,58,.16), transparent 62%),
    radial-gradient(60% 40% at 92% 12%,  rgba(140,50,48,.10), transparent 64%),
    radial-gradient(120% 60% at 50% 108%,rgba(30,4,5,.34),    transparent 72%);
}
.atmosfera > * { position: relative; z-index: 2; }

/* Retícula técnica: sin desvanecer se ve a wireframe; con máscara, a
   documento técnico. Es lenguaje gratis para una empresa de auditoría. */
.reticula { position: relative; isolation: isolate; }
.reticula::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    repeating-linear-gradient(to right,  var(--linea) 0 1px, transparent 1px 96px),
    repeating-linear-gradient(to bottom, var(--linea) 0 1px, transparent 1px 96px);
  -webkit-mask-image: radial-gradient(70% 58% at 50% 38%, #000 35%, transparent 100%);
          mask-image: radial-gradient(70% 58% at 50% 38%, #000 35%, transparent 100%);
}
.reticula > * { position: relative; z-index: 2; }

/* Bisel: borde de 1px con degradado. Simula que la luz pega arriba.
   Es lo que hace que un panel se sienta físico. */
.bisel {
  border: 1px solid transparent;
  border-radius: var(--radio-lg);
  background:
    linear-gradient(var(--superficie), var(--superficie)) padding-box,
    linear-gradient(160deg,
      color-mix(in oklab, var(--brand-200) 26%, transparent),
      color-mix(in oklab, var(--brand-200) 6%, transparent) 38%,
      transparent 62%,
      color-mix(in oklab, var(--brand-200) 13%, transparent)) border-box;
  box-shadow: inset 0 1px 0 rgba(254,204,198,.06), var(--sombra);
}
/* En claro el bisel guinda sobre papel blanco casi no se ve; ahí el volumen
   lo tiene que dar una línea real, no un degradado de 6% de opacidad. */
:root:not([data-tema="oscuro"]) .bisel {
  background:
    linear-gradient(var(--superficie), var(--superficie)) padding-box,
    linear-gradient(160deg, var(--linea-2), var(--linea-1) 45%, var(--linea-1)) border-box;
}

/* Si la última sección de la página va A SANGRE (banda guinda o tinta), el
   pie va pegado a ella. Con el margen fijo de 6rem quedaba una franja de papel
   vacía entre la banda y el pie, que se lee como contenido faltante. */
main:has(> [data-sangre]:last-child) + footer,
main:has(> :last-child > [data-sangre]:last-child) + footer { margin-top: 0; }

/* Costuras entre secciones: variar CÓMO se tocan es parte del ritmo. */
.filete {
  height: 1px; border: 0;
  background: linear-gradient(90deg, transparent, var(--linea) 15%, var(--linea) 85%, transparent);
}
.solape { margin-top: clamp(-7rem, -6vw, -3.5rem); position: relative; z-index: 2; }

/* ═══ Movimiento ══════════════════════════════════════════════════════════
   ⛔ EL MOVIMIENTO DEL PORTAL NO SE HEREDA DEL SISTEMA OPERATIVO.

   Aquí vivía la red que lo apagaba todo: un
   `*, *::before, *::after { animation-duration:.01ms !important }` bajo
   `prefers-reduced-motion: reduce`. Con esa regla puesta, cualquier animación
   nueva nacía muerta para quien tuviera apagados los efectos de Windows —que
   es el caso del dueño, medido con `SPI_GETCLIENTAREAANIMATION`—.

   Se retira por la misma razón que el tema no consulta `prefers-color-scheme`
   (ver `tema.js`): una casa institucional se presenta como decidió su dueño,
   no como quedó configurada la laptop de quien entra. En el tablero el
   movimiento además no es adorno: es lo que enseña qué barra se convirtió en
   cuál al mover un filtro.

   Esto vale SÓLO para el portal. El `tokens.css` del sitio público es otro
   archivo y conserva su respeto a la preferencia del sistema. ══════════════ */
@supports (animation-timeline: view()) {
  [data-revela] {
    animation: revelar linear both;
    animation-timeline: view();
    animation-range: entry 8% cover 30%;
  }
}
@keyframes revelar {
  from { opacity: 0; transform: translateY(1.5rem); }
  to   { opacity: 1; transform: none; }
}

/* Transición entre páginas: estándar web, cero JavaScript. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: vt-sale .26s var(--e-inout) both; }
::view-transition-new(root) { animation: vt-entra .4s var(--e-salida) both; }
@keyframes vt-sale  { to   { opacity: 0; transform: translateY(-6px); } }
@keyframes vt-entra { from { opacity: 0; transform: translateY(8px); } }
