/* ═══════════════════════════════════════════════════════════════════════════
   COMPONENTES DE ÉPOCA · base.css — LA ESTRUCTURA
   Contrato: design-system/05-contrato-componentes-epoca.md  (manda sobre el gusto)

   QUÉ ES ESTE FICHERO
   El esqueleto de los 8 componentes `c-*`: caja, layout, jerarquía tipográfica,
   estados (reposo/hover/foco/activo/deshabilitado), foco visible y movimiento
   reducido. Nada más.

   QUÉ **NO** ES
   Una piel. Aquí no hay ni un pigmento, ni un relieve, ni una fibra de papel, ni
   un remache, ni un cristal. Eso vive en epoca-1.css … epoca-5.css.

   ── LA REGLA ABSOLUTA ──────────────────────────────────────────────────────
   Ni un color, ni un radio, ni una duración, ni una familia escritos a mano.
   TODO sale de `var(--e-*)`. Un literal aquí dentro es un bug, no una decisión.
   La única excepción es el bloque §1 (`:root`), que ES el sitio donde viven los
   valores: es la época 5 de emergencia para que una página sin `data-epoca` no
   se quede desnuda.

   ── POR QUÉ FUNCIONA EL CAMBIO DE ÉPOCA (especificidad) ────────────────────
   Base usa selectores de UNA clase → (0,1,0) o (0,2,0) con pseudoclase.
   Cada época usa `html[data-epoca="N"] .c-*` → (0,2,0) o más, y además se carga
   DESPUÉS. Resultado: la piel siempre gana sin necesitar `!important`.
   Orden de carga obligatorio:  base.css → epoca-1 … epoca-5.

   ── LA TRAMPA QUE ESTE FICHERO EVITA (criterio de aceptación §5) ───────────
   `--e-aire` recorre 12px → 40px. Si los paddings salieran de él en crudo, un
   panel mediría casi el triple en la cabina que en la cueva y CUALQUIER subpágina
   se rompería al cambiar de era. Por eso hay dos escalas distintas (§1.2):
     · lo que ocupa la caja POR DENTRO  → escala comprimida (`--e-pad-*`)
     · lo que separa las cajas ENTRE SÍ → `--e-aire` en crudo (lo pone la página)
   Así el carácter se siente y la geometría no se desmadra: la variación de alto
   entre la época 1 y la 5 se queda en ~15%, por debajo del ±20% del contrato.

   ── CAVEAT DE LAS ESCALAS DERIVADAS ────────────────────────────────────────
   `--e-pad-caja` y compañía se declaran en `:root`, o sea SOBRE `<html>`, y ahí
   sustituyen el `--e-aire` que gane la cascada en ese mismo elemento. Como cada
   época declara sus tokens en `html[data-epoca="N"]` (el mismo `<html>`), todo
   cuadra. Lo que NO funciona es redeclarar `--e-aire` en un contenedor interior
   esperando que los paddings cambien: las derivadas ya se resolvieron arriba.
   Regla: los tokens de época se declaran en `<html>`. Punto.

   ── REGISTRO DE CAMBIOS ────────────────────────────────────────────────────
   TIRADA 10 · 2026-08-13 (contrato 23) — todo ADITIVO salvo dos listas de
   selectores que CRECEN sin cambiar ni un valor:
     · §1.3   token nuevo `--e-peligro` (defecto = el rojo frío de la Cabina)
     · §4     `.c-panel__cuerpo strong` → `:is(b, strong)`   [lista, no valor]
     · §13.5  regla nueva `.c-pie__enlaces a[aria-current]`
     · §16.2  la investigación de lo que el navegador deja tocar de la casilla
     · §16.4  `.c-cabecera__lead strong` → `:is(b, strong)`  [lista, no valor]
     · §16.14 … §16.20  las seis variantes de paridad y su pasada a 390px
   Ni un valor existente editado, ni un selector retirado: lo de antes de esta
   tirada se comporta exactamente igual, y así está medido (0 píxeles de
   diferencia en los dos muestrarios, en las cinco épocas, a 1400 y a 700).
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   1 · :root — TOKENS DE EMERGENCIA + ESCALAS DERIVADAS
   ─────────────────────────────────────────────────────────────────────────── */

/* 1.1 · La época 5 (Cabina) como red de seguridad.
   Valores tomados de la demo VALIDADA por Bernat (`demo-cabina/demo.html`) y de
   la paleta de la época 5 del contrato 01 §1. Si la página trae `data-epoca`,
   estos 18 tokens los pisa la hoja de esa época y aquí no queda nada vivo. */
:root{
  /* — color — */
  --e-fondo:          #06070A;                 /* grafito profundo FRÍO */
  --e-fondo-2:        #0B0D12;
  --e-sup:            #11141A;                 /* superficie */
  --e-tinta:          #EEF1F6;
  --e-tinta-2:        #A9B2C0;                 /* el gris más apagado que aún es texto */
  --e-linea:          rgba(238,241,246,.14);   /* el filo */
  --e-acento:         #FF6A1F;                 /* la brasa: el naranja que no cambia nunca */
  --e-acento-nucleo:  #FFC08A;                 /* núcleo claro de todo resplandor */
  --e-halo:           rgba(255,106,31,.45);
  --e-ok:             #FFC08A;

  /* — carácter — */
  --e-radio:          14px;
  --e-grosor:         1px;
  --e-aire:           clamp(28px, 5vw, 40px);
  --e-vel:            130ms;
  --e-tracking:       -.035em;

  /* — tipos — */
  --e-display: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --e-cuerpo:  'Inter Tight', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --e-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* 1.2 · ESCALAS DERIVADAS — no son tokens de época, son la geometría del sistema.
     Una época puede redeclararlas si de verdad lo necesita, pero no le hace falta:
     salen solas de su `--e-aire`. La forma `A + aire·k` es deliberada: el término
     fijo es el suelo que impide que la cueva quede impracticable y el factor `k`
     es lo que se nota del carácter sin romper el ±20% de alto. */
  --e-pad-caja:   calc(15px + var(--e-aire) * .22);   /* padding interior de un bloque */
  --e-pad-corto:  calc(9px  + var(--e-aire) * .12);   /* padding de cabeceras y pies */
  --e-gap:        calc(6px  + var(--e-aire) * .22);   /* separación entre piezas hermanas */
  --e-alto-ctrl:  calc(38px + var(--e-aire) * .22);   /* alto mínimo de botón e input */

  /* 1.3 · EXTENSIONES CON DEFECTO — declaradas aquí para que existan SIEMPRE.
     Cada época puede redeclararlas; ninguna está obligada. */
  --e-curva:  cubic-bezier(.22,.61,.36,1);  /* una sola curva; el carácter lo pone --e-vel */
  --e-nada:   transparent;                  /* el vacío de los degradados y las mezclas */
  --e-peso-display: 600;                    /* ⚠ familia de un solo peso (Anton) → ponla a 400 */
  --e-peso-fuerte:  700;                    /* cifras de instrumento */

  /* EL AVISO DEL MATERIAL (tirada 10, 2026-08-13). No es un segundo acento: es
     el color con el que cada época dice «esto se pierde». Lo usan `--peligro`
     (§16.14) y el signo negativo de `--moneda` (§16.18), y NADA más.
     Aquí vale el rojo FRÍO de la Cabina, que es la red de seguridad de §1.1;
     cada época lo redeclara con el rojo que ya tenía: é1 `--e1-error`, é2
     `--e2-grieta`, é4 `--e4-oxido`, é5 `--e5-alerta`. La 3 es la excepción y
     está explicada donde toca: su rojo es de CONTEXTO (minio sobre el taller,
     rúbrica dentro de una hoja), así que no puede resolverse en `<html>` —
     `epoca-3.css` lo redeclara sobre las propias piezas. */
  --e-peligro: #FF6B7A;

  /* 1.4 · GEOMETRÍA DEL ARMAZÓN (§13) — la medida del MUNDO, no la de las piezas.
     Estas cuatro son del contrato 07 §B y NO se derivan del carácter: el ancho de
     lectura no cambia porque cambie la era. Lo que sí respira con `--e-aire` es la
     barra, y con el mismo freno de §1.2 (término fijo + factor pequeño). Medido
     en las 5 épocas: barra 49,1 → 56,4px (+15%) y pie 52,3 → 58,7px (+12%), con
     margen de sobra bajo el ±20% del contrato para que las pieles puedan añadir
     su propio filete sin salirse. */
  --e-marco:          1180px;                    /* el ancho de la sala */
  --e-marco-estrecho: 760px;                     /* `c-marco--estrecho`: la columna de leer */
  --e-marco-pad:      clamp(20px, 3vw, 32px);    /* 32→20px, contrato 07 §B */
  --e-alto-barra:     calc(46px + var(--e-aire) * .26);
  --e-capa-barra:     30;                        /* z-index de la barra pegajosa */

  /* LA RESERVA DEL ANCLA (§13.6). Una barra pegajosa se come el destino de
     cualquier `href="#loquesea"`: el navegador para el scroll en el borde de la
     PÁGINA, no en el borde de lo que se ve, y el titular de la sección aterriza
     debajo de la barra. El sumando fijo no es holgura estética: es que la piel
     de una época puede SALIRSE de la caja de la barra (la cornisa de la cueva
     cuelga 11px con el canto roto, y por esas mellas se ve pasar el texto). Se
     mide contra el borde de abajo REAL, no contra `--e-alto-barra`.
     Medido a 1440px: barra 49,1→56,4px · reserva 65,1→72,4px · el peor caso
     (época 1, con sus 11px de saliente) deja 5px de aire limpio. */
  --e-ancla:          calc(var(--e-alto-barra) + 16px);
}


/* 1.5 · RED DE SEGURIDAD DEL MUNDO. Los tokens de emergencia no sirven de nada
   si nadie pinta el fondo: sin `data-epoca` la página sería tinta clara sobre
   blanco. Se pinta el CANVAS, no `.c-sala`, y solo cuando no hay época: así
   ninguna piel tiene que competir con esta línea (las épocas 2, 4 y 5 pintan
   `<html>` y dejan el body transparente — si esto fuera un fondo opaco en la
   sala, se las taparía). */
html:not([data-epoca]){ background: var(--e-fondo); }


/* ───────────────────────────────────────────────────────────────────────────
   2 · RESET MÍNIMO Y FOCO
   Lo justo para que cinco mundos partan del mismo cero. El fondo de la PÁGINA no
   se pinta aquí (es cosa de la página o de la piel de época).
   ─────────────────────────────────────────────────────────────────────────── */
*, *::before, *::after{ box-sizing: border-box; }

/* Foco visible SIEMPRE, del grosor de la época pero nunca por debajo de 2px:
   la belleza de un mundo no puede costar la navegación por teclado. */
:focus-visible{
  outline: 2px solid var(--e-acento);          /* atajo simple por si un motor no resuelve el max() */
  outline-width: max(2px, var(--e-grosor));
  outline-offset: 3px;
}

::selection{ background: var(--e-halo); color: var(--e-tinta); }


/* ───────────────────────────────────────────────────────────────────────────
   3 · BOTÓN  ·  .c-boton  ·  --brasa (lo encendido) / --fantasma (lo disponible)
   ─────────────────────────────────────────────────────────────────────────── */
.c-boton{
  position: relative;            /* gancho de época */
  isolation: isolate;            /* garantiza que un ::before z-index:-1 caiga
                                    ENCIMA del fondo del botón y DEBAJO del texto */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--e-gap) * .55);
  min-height: var(--e-alto-ctrl);
  padding-block: calc(var(--e-pad-corto) * .55);
  padding-inline: calc(var(--e-pad-caja) * 1.05);
  max-width: 100%;

  border: var(--e-grosor) solid var(--e-linea);
  border-radius: var(--e-radio);
  background: none;
  color: var(--e-tinta);

  font-family: var(--e-display);
  font-weight: var(--e-peso-display);
  font-size: 15px;
  line-height: 1.15;
  letter-spacing: var(--e-tracking);
  text-align: center;
  text-decoration: none;         /* sirve igual sobre <a class="c-boton"> */

  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
  transition:
    transform    var(--e-vel) var(--e-curva),
    background   var(--e-vel) linear,
    border-color var(--e-vel) linear,
    box-shadow   var(--e-vel) linear,
    color        var(--e-vel) linear,
    filter       var(--e-vel) linear;
}

/* — variante BRASA: lo único encendido de la pantalla —
   El texto va con `--e-fondo` a propósito: en las cuatro épocas oscuras eso es
   tinta negra sobre naranja, y en la 3 (papel) es papel sobre el sello rojo.
   Un solo token resuelve las dos direcciones de contraste. */
.c-boton--brasa{
  background: var(--e-acento);
  border-color: var(--e-acento);
  color: var(--e-fondo);
  box-shadow: 0 10px 30px -14px var(--e-halo);
}
.c-boton--brasa:hover{
  background: var(--e-acento-nucleo);
  border-color: var(--e-acento-nucleo);
  box-shadow: 0 14px 38px -12px var(--e-halo);
  transform: translateY(-2px);
}

/* — variante FANTASMA: presente, no encendida — */
.c-boton--fantasma{
  background: none;
  border-color: var(--e-linea);
  color: var(--e-tinta);
}
.c-boton--fantasma:hover{
  background: color-mix(in oklab, var(--e-tinta) 8%, var(--e-nada));
  border-color: color-mix(in oklab, var(--e-tinta) 40%, var(--e-linea));
}

/* — TAMAÑO Y OCUPACIÓN: geometría, no pigmento —
   Los dos salen del marcado CONGELADO de la segunda tirada (contrato 08 §2): la
   ficha de precio pide `c-boton--brasa c-boton--bloque` y la tabla pide
   `c-boton--fantasma c-boton--sm`. Sin ellos aquí, cada componente nuevo se
   inventaría su propio tamaño de botón dentro de su fichero y el sistema
   tendría ocho botones pequeños distintos. Son estructura: van en base, una vez.
   Ni la variante ni la piel cambian — solo la caja. */
.c-boton--bloque{
  display: flex;
  width: 100%;
}
.c-boton--sm{
  min-height: calc(var(--e-alto-ctrl) * .72);
  padding-block: calc(var(--e-pad-corto) * .34);
  padding-inline: calc(var(--e-pad-caja) * .6);
  font-size: 13px;
}

/* — estados comunes — */
.c-boton:focus-visible{ outline-color: var(--e-acento); }
.c-boton--brasa:focus-visible{ outline-color: var(--e-tinta); }  /* naranja sobre naranja no se ve */
.c-boton:active{ transform: translateY(0) scale(.985); }
.c-boton:disabled,
.c-boton[aria-disabled="true"]{
  opacity: .45;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
  filter: saturate(.4);
}


/* ───────────────────────────────────────────────────────────────────────────
   4 · PANEL  ·  .c-panel  (+ __cabecera __cuerpo __pie __meta, --destacado)
   La caja donde vive todo lo demás: pared / estela / hoja / chapa / cristal.
   ─────────────────────────────────────────────────────────────────────────── */
.c-panel{
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  min-width: 0;                                    /* no desborda dentro de una rejilla */
  border: var(--e-grosor) solid var(--e-linea);
  border-radius: var(--e-radio);
  background: var(--e-sup);
  color: var(--e-tinta);
  transition:
    transform    var(--e-vel) var(--e-curva),
    border-color var(--e-vel) linear,
    box-shadow   var(--e-vel) linear;
}
.c-panel:hover{ border-color: color-mix(in oklab, var(--e-tinta) 22%, var(--e-linea)); }

.c-panel__cabecera,
.c-panel__pie{
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-gap);
  flex-wrap: wrap;
  padding: var(--e-pad-corto) var(--e-pad-caja);
}
.c-panel__cabecera{ border-bottom: var(--e-grosor) solid var(--e-linea); }
.c-panel__pie{ margin-top: auto; border-top: var(--e-grosor) solid var(--e-linea); }

.c-panel__cuerpo{
  flex: 1 1 auto;
  padding: var(--e-pad-caja);
  font-family: var(--e-cuerpo);
  font-size: 15px;
  line-height: 1.55;
  color: var(--e-tinta-2);
}
.c-panel__cuerpo > * + *{ margin-top: calc(var(--e-gap) * .7); }
/* `b` Y `strong`, no solo `strong` (tirada 10, 2026-08-13). El marcado real de
   la web usa los dos indistintamente para el mismo énfasis, y con solo `strong`
   cubierto el `<b>` se quedaba en `--e-tinta-2` mientras su hermano subía a
   `--e-tinta`: dos pesos y dos tintas distintas para la misma intención, medido
   en é2, é4 y é5 (en é1 y é3 la piel ya cubría los dos y coincidían).
   Cero cambios de valor: la lista de selectores es lo único que crece. */
.c-panel__cuerpo :is(b, strong){ color: var(--e-tinta); }

/* la etiqueta de instrumento: mono en micro-mayúsculas.
   El tracking NO puede heredar el de titulares (la cabina lo tiene NEGATIVO y en
   micro-mayúsculas eso es ilegible): se le pone suelo con max(). */
.c-panel__meta{
  font-family: var(--e-mono);
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: max(.06em, var(--e-tracking));
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--e-tinta-2);
}

/* — el panel encendido: uno por pantalla — */
.c-panel--destacado{
  border-color: color-mix(in oklab, var(--e-acento) 55%, var(--e-linea));
  box-shadow:
    0 0 0 max(1px, var(--e-grosor)) var(--e-halo),
    0 26px 70px -34px var(--e-halo);
}
.c-panel--destacado .c-panel__cabecera,
.c-panel--destacado .c-panel__pie{
  border-color: color-mix(in oklab, var(--e-acento) 35%, var(--e-linea));
}
.c-panel--destacado .c-panel__meta{ color: var(--e-acento); }


/* ───────────────────────────────────────────────────────────────────────────
   5 · CAMPO  ·  .c-campo (+ __etiqueta __input __ayuda, --error)
   Rejilla de 3 filas con NOMBRE, para que una época pueda colocar un ::before
   exactamente encima del input sin pedir un `<div>` nuevo (§10.3).
   ─────────────────────────────────────────────────────────────────────────── */
.c-campo{
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "etiqueta"
    "campo"
    "ayuda";
  min-width: 0;
}

.c-campo__etiqueta{
  grid-area: etiqueta;
  margin-bottom: calc(var(--e-gap) * .38);
  font-family: var(--e-cuerpo);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--e-tinta);
}

.c-campo__input{
  grid-area: campo;
  width: 100%;
  min-width: 0;
  min-height: var(--e-alto-ctrl);
  padding-block: calc(var(--e-pad-corto) * .55);
  padding-inline: calc(var(--e-pad-caja) * .72);

  border: var(--e-grosor) solid var(--e-linea);
  border-radius: var(--e-radio);
  background: var(--e-fondo-2);
  color: var(--e-tinta);

  font-family: var(--e-cuerpo);
  font-size: 15px;
  line-height: 1.4;
  -webkit-appearance: none;
          appearance: none;
  transition:
    border-color var(--e-vel) linear,
    background   var(--e-vel) linear,
    box-shadow   var(--e-vel) linear;
}
.c-campo__input::placeholder{ color: var(--e-tinta-2); opacity: 1; }
.c-campo__input:hover{ border-color: color-mix(in oklab, var(--e-tinta) 28%, var(--e-linea)); }
.c-campo__input:focus{ border-color: var(--e-acento); }
.c-campo__input:focus-visible{ outline-color: var(--e-acento); }
.c-campo__input:disabled{
  opacity: .5;
  cursor: not-allowed;
  background: var(--e-fondo);
}

.c-campo__ayuda{
  grid-area: ayuda;
  margin-top: calc(var(--e-gap) * .38);
  font-family: var(--e-cuerpo);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--e-tinta-2);
}

/* — error: no hay token de error en el contrato y no hace falta —
   `--e-acento` ya ES el rojo de rúbrica en la imprenta y la brasa en las demás:
   el color de "mírame" de cada época. */
.c-campo--error .c-campo__input{
  border-color: var(--e-acento);
  box-shadow: 0 0 0 max(1px, var(--e-grosor)) var(--e-halo);
}
.c-campo--error .c-campo__ayuda{ color: var(--e-acento); }


/* ───────────────────────────────────────────────────────────────────────────
   6 · DISTINTIVO  ·  .c-distintivo (+ --acento --ok)
   ─────────────────────────────────────────────────────────────────────────── */
.c-distintivo{
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--e-gap) * .35);
  padding-block: calc(var(--e-pad-corto) * .28);
  padding-inline: calc(var(--e-pad-corto) * .72);

  border: var(--e-grosor) solid var(--e-linea);
  border-radius: var(--e-radio);
  background: color-mix(in oklab, var(--e-tinta) 5%, var(--e-nada));
  color: var(--e-tinta-2);

  font-family: var(--e-mono);
  font-size: 10px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: max(.06em, var(--e-tracking));
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.c-distintivo--acento{
  border-color: color-mix(in oklab, var(--e-acento) 60%, var(--e-linea));
  background: color-mix(in oklab, var(--e-acento) 10%, var(--e-nada));
  color: var(--e-acento);
}
.c-distintivo--ok{
  border-color: color-mix(in oklab, var(--e-ok) 55%, var(--e-linea));
  background: color-mix(in oklab, var(--e-ok) 9%, var(--e-nada));
  color: var(--e-ok);
}


/* ───────────────────────────────────────────────────────────────────────────
   7 · INSTRUMENTO  ·  .c-instrumento (+ __cifra __etiqueta)
   El dato desnudo. La cifra manda; la etiqueta la nombra.
   ─────────────────────────────────────────────────────────────────────────── */
.c-instrumento{
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--e-gap) * .28);
  min-width: 0;
  padding: var(--e-pad-caja);
  border: var(--e-grosor) solid var(--e-linea);
  border-radius: var(--e-radio);
  background: var(--e-sup);
  transition: border-color var(--e-vel) linear, transform var(--e-vel) var(--e-curva);
}
.c-instrumento:hover{ border-color: color-mix(in oklab, var(--e-tinta) 22%, var(--e-linea)); }

.c-instrumento__cifra{
  font-family: var(--e-mono);
  font-weight: var(--e-peso-fuerte);
  font-size: clamp(28px, 3.4vw, 38px);
  line-height: 1;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  color: var(--e-tinta);
}
.c-instrumento__etiqueta{
  font-family: var(--e-mono);
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: max(.06em, var(--e-tracking));
  text-transform: uppercase;
  color: var(--e-tinta-2);
}


/* ───────────────────────────────────────────────────────────────────────────
   8 · PROGRESO  ·  .c-progreso > __pista > __relleno   ·   style="--valor:33"
   El relleno se mueve con `--valor`. El movimiento del dato es MÁS LENTO que el
   de la interfaz a propósito: se lee, no se dispara.
   ─────────────────────────────────────────────────────────────────────────── */
.c-progreso{
  position: relative;
  display: block;
  min-width: 0;
}
.c-progreso__pista{
  position: relative;
  isolation: isolate;
  overflow: hidden;                                  /* el relleno no se sale del carril */
  /* el carril es lo más fino del sistema: con un factor mayor, 12px→40px de aire
     lo engordaba un 36% y se saltaba el ±20% del contrato. Medido: +17%. */
  height: calc(9px + var(--e-aire) * .06);
  border-radius: var(--e-radio);
  background: color-mix(in oklab, var(--e-tinta) 16%, var(--e-nada));
}
.c-progreso__relleno{
  position: relative;
  isolation: isolate;
  height: 100%;
  width: calc(var(--valor, 0) * 1%);
  max-width: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--e-acento), var(--e-acento-nucleo));
  transition: width calc(var(--e-vel) * 4) var(--e-curva);
}


/* ───────────────────────────────────────────────────────────────────────────
   9 · NAVEGACIÓN  ·  .c-nav > .c-nav__item (.is-activa / [aria-current="page"])
   El subrayado de la activa va por `box-shadow: inset`, NO por ::after: los dos
   pseudos del item quedan libres para la piel de época.
   ─────────────────────────────────────────────────────────────────────────── */
.c-nav{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--e-gap) * .5);
  min-width: 0;
}
.c-nav__item{
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  padding-block: calc(var(--e-pad-corto) * .5);
  padding-inline: calc(var(--e-pad-corto) * .85);
  border-radius: var(--e-radio);
  background: none;
  color: var(--e-tinta-2);
  font-family: var(--e-cuerpo);
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.3;
  text-decoration: none;
  transition:
    color      var(--e-vel) linear,
    background var(--e-vel) linear,
    box-shadow var(--e-vel) linear;
}
.c-nav__item:hover{
  color: var(--e-tinta);
  background: color-mix(in oklab, var(--e-tinta) 7%, var(--e-nada));
}
.c-nav__item:active{ transform: translateY(1px); }
.c-nav__item.is-activa,
.c-nav__item[aria-current="page"]{
  color: var(--e-tinta);
  box-shadow: inset 0 calc(max(2px, var(--e-grosor)) * -1) 0 0 var(--e-acento);
}


/* ───────────────────────────────────────────────────────────────────────────
   10 · CABECERA DE SECCIÓN  ·  .c-cabecera (+ __kicker __titulo)
   ─────────────────────────────────────────────────────────────────────────── */
.c-cabecera{
  position: relative;
  isolation: isolate;
  display: grid;
  gap: calc(var(--e-gap) * .42);
  min-width: 0;
}
.c-cabecera__kicker{
  margin-block: 0;             /* fuera el `margin:1em 0` del navegador: es un <p>
                                   y la cabecera es rejilla, donde eso NO colapsa
                                   (mismo defecto que abajo, ver la nota del titular) */
  font-family: var(--e-mono);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: max(.07em, var(--e-tracking));
  text-transform: uppercase;
  color: var(--e-acento);
}
.c-cabecera__titulo{
  position: relative;
  isolation: isolate;
  /* fuera el margen de agente de usuario del h1/h2/h3 que haga de titular. La
     cabecera es una REJILLA (§10 arriba) y ahí los márgenes NO colapsan: sin
     este reset, el `margin-block` del navegador (0,67em en un h1, 0,83em en un
     h2 — es decir 26,8px / 33,2px con el titular a 40px) entraba entero arriba
     Y abajo de la fila, partiendo la retícula en cualquier página que use este
     componente. Es el mismo defecto que `epoca-3.css` §8 ya documentaba para
     el kicker (arriba); hasta ahora `views/epoca/modules.ejs` lo compensaba a
     mano en su <style> de página — con el reset aquí, esa línea de la página
     queda redundante (sigue en 0, no se toca sola). Vive en base y no en cada
     página: es estructura del componente, no gusto de una vista. */
  margin-block: 0;
  font-family: var(--e-display);
  font-weight: var(--e-peso-display);
  font-size: clamp(26px, 3.6vw, 40px);
  line-height: 1.06;
  letter-spacing: var(--e-tracking);
  color: var(--e-tinta);
  text-wrap: balance;
}


/* ═══════════════════════════════════════════════════════════════════════════
   11 · CONTRATO DE GANCHOS — lo que las pieles de época pueden usar
   ═══════════════════════════════════════════════════════════════════════════

   base.css NO gasta ni un solo `::before`/`::after` de los `c-*`. Los 20 están
   libres. Aquí solo se dejan PREPARADOS: la piel de época pone `content:""` y su
   pintura, y la pieza ya nace colocada.

   ── LA CONVENCIÓN DE CAPAS (memorízala, es toda la gramática) ──────────────
     ::before  = capa de MATERIA  → z-index:-1 → debajo del texto, ENCIMA del
                 fondo del componente. Pigmento, veta, fibra, hollín, cristal.
     ::after   = capa de LUZ      → z-index: 1 → encima de todo, sin ratón.
                 Halo, chispa, filo encendido, sello, remache, brillo.
   Funciona porque cada componente lleva `isolation:isolate`: el -1 no se escapa
   detrás del fondo, se queda exactamente entre el fondo y el texto.

   ── LO QUE YA VIENE PUESTO ────────────────────────────────────────────────
   `position:absolute; inset:0; border-radius:inherit; pointer-events:none`
   (el radio se hereda solo → la materia se recorta con la forma de la época).
   Si tu adorno no es una capa a sangre, písalo: `inset:auto; right:…; top:…`.
   Si lo quieres en línea con el texto (una viñeta, un `·`), píselo también:
   `position:static; z-index:auto`.
   OJO CON EL BORDE: `inset:0` resuelve contra la caja de RELLENO, así que la capa
   llega al filo interior del borde y lo deja ver (medido: 179px de capa en un
   botón de 181px con filo de 1px). Si tu textura tiene que pasar por debajo del
   borde: `inset: calc(var(--e-grosor) * -1)`.

   ── DÓNDE HAY GANCHO ──────────────────────────────────────────────────────
   `.c-boton` · `.c-panel` · `.c-panel__cabecera` · `.c-panel__pie` · `.c-campo`
   · `.c-distintivo` · `.c-instrumento` · `.c-progreso__pista`
   · `.c-progreso__relleno` · `.c-nav__item` · `.c-cabecera` · `.c-cabecera__titulo`
   Los cinco componentes del ARMAZÓN (`.c-sala` `.c-barra-marca` `.c-marco`
   `.c-rejilla` `.c-pie`) tienen sus propios ganchos y su propia gramática, con
   una excepción que cambia las reglas (las capas de la sala son FIJAS): §14.

   ── LAS TRES EXCEPCIONES QUE HAY QUE SABER ────────────────────────────────
   1. `<input>` NO admite pseudos. El gancho del campo es `.c-campo::before/::after`
      y ya viene colocado sobre la casilla: la rejilla tiene el área `campo` con
      nombre, así que el pseudo cae clavado encima del input (por eso van con
      `z-index:1`, no -1: debajo quedarían tapados por el fondo del input).
      Para textura DENTRO del input, usa `background-image` en el propio input.
   2. `.c-progreso__pista` recorta (`overflow:hidden`). Si tu época quiere que la
      luz se salga del carril, declara `overflow:visible` en la pista y recorta
      donde te convenga.
   3. Los halos que van FUERA de la caja no necesitan pseudo ni overflow: un
      `box-shadow` nunca se recorta.

   ── LO QUE NO ES GANCHO PERO ES TUYO ──────────────────────────────────────
   · `html[data-epoca="N"] body` → el fondo de la página (base.css no lo pinta).
   · Los 18 tokens de §2 del contrato + estas extensiones opcionales:
     `--e-curva` (curva única), `--e-nada` (transparent), `--e-peso-display`
     (⚠ Anton solo tiene 400: la época 1 DEBE bajarlo o el navegador lo falsea),
     `--e-peso-fuerte`, y las derivadas `--e-pad-caja` `--e-pad-corto` `--e-gap`
     `--e-alto-ctrl` si de verdad necesitas otra geometría.
   · `.eN-*` para tus adornos, siempre colgando de un `c-*` existente.
   ═════════════════════════════════════════════════════════════════════════ */

.c-boton::before,            .c-boton::after,
.c-panel::before,            .c-panel::after,
.c-panel__cabecera::before,  .c-panel__cabecera::after,
.c-panel__pie::before,       .c-panel__pie::after,
.c-distintivo::before,       .c-distintivo::after,
.c-instrumento::before,      .c-instrumento::after,
.c-progreso__pista::before,  .c-progreso__pista::after,
.c-progreso__relleno::before,.c-progreso__relleno::after,
.c-nav__item::before,        .c-nav__item::after,
.c-cabecera::before,         .c-cabecera::after,
.c-cabecera__titulo::before, .c-cabecera__titulo::after{
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}
/* materia debajo del texto · luz encima */
.c-boton::before,
.c-panel::before,
.c-panel__cabecera::before,
.c-panel__pie::before,
.c-distintivo::before,
.c-instrumento::before,
.c-progreso__pista::before,
.c-progreso__relleno::before,
.c-nav__item::before,
.c-cabecera::before,
.c-cabecera__titulo::before{ z-index: -1; }

.c-boton::after,
.c-panel::after,
.c-panel__cabecera::after,
.c-panel__pie::after,
.c-distintivo::after,
.c-instrumento::after,
.c-progreso__pista::after,
.c-progreso__relleno::after,
.c-nav__item::after,
.c-cabecera::after,
.c-cabecera__titulo::after{ z-index: 1; }

/* el campo es rejilla: sus pseudos son ITEMS, y caen sobre la casilla del input */
.c-campo::before,
.c-campo::after{
  grid-area: campo;
  z-index: 1;
  border-radius: var(--e-radio);
  pointer-events: none;
}


/* ───────────────────────────────────────────────────────────────────────────
   12 · MOVIMIENTO REDUCIDO — todo congelado en su estado final
   No se pierde ni una información: lo que se movía, aparece ya colocado.
   ─────────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  .c-boton:hover,
  .c-boton:active,
  .c-nav__item:active,
  .c-instrumento:hover,
  .c-panel:hover{ transform: none !important; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   13 · ARMAZÓN — LA ESTRUCTURA DEL MUNDO
   Contrato: design-system/07-contrato-vida-y-armazon.md §B (marcado congelado)
   ═══════════════════════════════════════════════════════════════════════════

   Los 8 componentes son las PIEZAS. Estos 5 son la SALA donde viven. Sin ellos,
   cambiar de época cambia los objetos sobre un fondo que no cambia — y eso no es
   viajar en el tiempo, es cambiar de muebles. Con ellos, el atributo `data-epoca`
   cambia EL MUNDO: el aire, la barra, el ancho, el pie.

   Misma ley que arriba: aquí solo hay geometría. Ni un pigmento, ni una fibra, ni
   un cristal. Todo `var(--e-*)`.

   ── EL REPARTO DE FONDOS (importante, se pisan entre sí si no se respeta) ──
     `<html>`          → el fondo INFINITO de la época (las épocas 2, 4 y 5 lo
                         pintan ahí con `background-attachment: fixed`).
     `.c-sala` (body)  → el ambiente: sus dos capas fijas (§14) y, si la piel lo
                         necesita, su propio fondo.
   base.css no pinta ninguno de los dos: solo los prepara.
   ─────────────────────────────────────────────────────────────────────────── */


/* ───────────────────────────────────────────────────────────────────────────
   13.1 · SALA  ·  .c-sala   (va en el <body>)
   Columna de altura completa: barra arriba, contenido que crece, pie que cae
   al fondo aunque la página tenga tres líneas. Dos mecanismos redundantes a
   propósito — el `flex:1 1 auto` del marco y el `margin-top:auto` del pie —
   porque una subpágina puede no tener marco, o tener tres.
   ─────────────────────────────────────────────────────────────────────────── */
.c-sala{
  position: relative;
  isolation: isolate;          /* las capas fijas de §14 se quedan DENTRO: encima
                                  del fondo de html, debajo del contenido */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;          /* móvil: la barra del navegador no roba altura */
  margin: 0;
  color: var(--e-tinta);
  font-family: var(--e-cuerpo);
}
.c-sala > .c-barra-marca,
.c-sala > .c-pie{ flex: 0 0 auto; }
.c-sala > .c-marco,
.c-sala > main{ flex: 1 1 auto; }


/* ───────────────────────────────────────────────────────────────────────────
   13.2 · BARRA DE MARCA  ·  .c-barra-marca (+ __marca __sub __nav __acciones)
   Pegajosa arriba y a sangre: el filo inferior cruza la pantalla entera, pero
   su contenido queda alineado al milímetro con el del `.c-marco`. Eso lo hace
   el `padding-inline: max(pad, (100% - marco)/2)` — sin un div envolvente, que
   el marcado está congelado.
   ─────────────────────────────────────────────────────────────────────────── */
.c-barra-marca{
  position: sticky;
  top: 0;
  z-index: var(--e-capa-barra);
  isolation: isolate;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-gap);
  min-height: var(--e-alto-barra);
  padding-block: calc(var(--e-pad-corto) * .42);
  padding-inline: max(var(--e-marco-pad), calc((100% - var(--e-marco)) / 2));
  border-bottom: var(--e-grosor) solid var(--e-linea);

  /* OPACA POR DEFECTO, y es deliberado: una barra pegajosa sin fondo deja pasar
     el texto que scrollea por debajo y no hay contraste que valga. La piel de
     cada época la convierte en su material (piedra, papel, chapa, cristal). */
  background: var(--e-fondo);
}

.c-barra-marca__marca{
  display: inline-flex;
  align-items: baseline;
  gap: calc(var(--e-gap) * .42);
  min-width: 0;
  font-family: var(--e-display);
  font-weight: var(--e-peso-display);
  font-size: 17px;
  line-height: 1.1;
  letter-spacing: var(--e-tracking);
  color: var(--e-tinta);
  text-decoration: none;
  white-space: nowrap;
}
/* el marcado congelado no deja espacio entre "becama" y el sub: lo pone el gap */
.c-barra-marca__sub{
  font-family: var(--e-mono);
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: max(.08em, var(--e-tracking));
  text-transform: uppercase;
  color: var(--e-tinta-2);
}

.c-barra-marca__nav{ min-width: 0; }

.c-barra-marca__acciones{
  display: flex;
  align-items: center;
  gap: calc(var(--e-gap) * .5);
  flex-wrap: wrap;
  margin-left: auto;            /* la acción siempre a la derecha */
  min-width: 0;
}
/* un botón de barra es el mismo componente, un punto más apretado: la barra no
   puede crecer el 30% porque dentro haya un botón */
.c-barra-marca__acciones .c-boton{
  min-height: calc(var(--e-alto-ctrl) * .82);
  padding-inline: calc(var(--e-pad-caja) * .82);
  font-size: 14px;
}


/* ───────────────────────────────────────────────────────────────────────────
   13.3 · MARCO  ·  .c-marco (+ --estrecho)
   El ancho de la sala. 1180px, o 760px cuando lo que hay dentro es prosa.
   ─────────────────────────────────────────────────────────────────────────── */
.c-marco{
  position: relative;
  isolation: isolate;
  width: 100%;
  max-width: var(--e-marco);
  min-width: 0;
  margin-inline: auto;
  padding-inline: var(--e-marco-pad);
  padding-block: var(--e-aire);   /* separación entre cajas → aire en crudo (§1.2) */
}
.c-marco--estrecho{ max-width: var(--e-marco-estrecho); }


/* ───────────────────────────────────────────────────────────────────────────
   13.4 · REJILLA  ·  .c-rejilla (+ --2 --3 --4)
   El hueco ES `--e-aire`: la respiración de la época se ve, sobre todo, en lo
   que separa las cajas. `minmax(0,1fr)` en todas partes — una columna `1fr` con
   un `<pre>` dentro desborda, y la cueva no perdona.
   ─────────────────────────────────────────────────────────────────────────── */
.c-rejilla{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--e-aire);
  min-width: 0;
}
.c-rejilla > *{ min-width: 0; }
.c-rejilla--2{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
.c-rejilla--3{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
.c-rejilla--4{ grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Escalón intermedio: 4 columnas en una tableta son 4 tiras ilegibles. El
   contrato solo exige el colapso a 1 en ≤760px; este paso previo es geometría,
   no gusto, y ninguna época lo tiene que repetir. */
@media (max-width: 1080px){
  .c-rejilla--3,
  .c-rejilla--4{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px){
  .c-rejilla--2,
  .c-rejilla--3,
  .c-rejilla--4{ grid-template-columns: minmax(0, 1fr); }
}


/* ───────────────────────────────────────────────────────────────────────────
   13.5 · PIE  ·  .c-pie (+ __marca __enlaces)
   Mono pequeño y línea fina. Se alinea con el marco por el mismo truco que la
   barra, y cae al fondo por `margin-top:auto`.
   ─────────────────────────────────────────────────────────────────────────── */
.c-pie{
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--e-gap);
  margin-top: auto;
  padding-block: calc(15px + var(--e-aire) * .15);   /* freno del ±20%: ver §1.4 */
  padding-inline: max(var(--e-marco-pad), calc((100% - var(--e-marco)) / 2));
  border-top: var(--e-grosor) solid var(--e-linea);

  font-family: var(--e-mono);
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: max(.06em, var(--e-tracking));
  text-transform: uppercase;
  color: var(--e-tinta-2);
}
.c-pie__marca{ min-width: 0; }
.c-pie__enlaces{
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--e-gap) * .9);
  min-width: 0;
}
.c-pie__enlaces a{
  color: var(--e-tinta-2);
  text-decoration: none;
  transition: color var(--e-vel) linear;
}
.c-pie__enlaces a:hover{ color: var(--e-tinta); }
/* LA PÁGINA EN LA QUE ESTÁS (tirada 10, 2026-08-13). Las cinco legales se
   enlazan entre sí por el pie y hasta hoy la activa se marcaba SOLO en la
   semántica (`aria-current="page"`): quien no usa lector de pantalla no tenía
   ni una pista de dónde estaba. Piel mínima a propósito —es un pie, no una
   navegación—: la tinta sube a plena y aparece el subrayado, que es el gesto
   del material (el mismo que ya usa el hover de la é3). Ni fondo, ni caja, ni
   peso: eso ya sería un menú. El grosor sale del carácter de la época con un
   suelo de 1px, y el `offset` en `em` para que siga al tamaño de la letra.

   ⚠ ESTA REGLA SOLA NO SE VE, y es correcto que sea así: LAS CINCO ÉPOCAS
   repintan `.c-pie__enlaces a` con más especificidad que ella (cuatro le quitan
   además el subrayado), porque el pie es de las piezas que más carácter llevan.
   Así que cada `epoca-N.css` trae su propia línea para el enlace actual, con el
   gesto de su material: el trazo ya pintado en la Cueva, el filete tallado en la
   Piedra, el subrayado del colofón en el Papel, el troquel en el Hierro y la
   tinta encendida en la Cabina. Lo de aquí es el suelo del sistema: lo que verá
   una época futura que no se meta con el pie. */
.c-pie__enlaces a[aria-current]{
  color: var(--e-tinta);
  text-decoration: underline;
  text-decoration-thickness: max(1px, calc(var(--e-grosor) * .5));
  text-underline-offset: .26em;
}


/* ───────────────────────────────────────────────────────────────────────────
   13.6 · EL ANCLA NO SE ESCONDE BAJO LA BARRA
   Es la contrapartida obligatoria de `position:sticky` en §13.2: en el momento
   en que la barra flota sobre el contenido, TODO destino de un enlace interno
   necesita reservar su alto. Sin esto, pinchar «Armazón» en el índice deja el
   titular de la sección tapado (medido a 390px: 77px de la sección, incluido su
   rótulo entero, debajo de la barra — o sea, invisible).

   Va sobre `[id]` y no sobre una lista de clases a propósito: el ancla la
   decide la PÁGINA, no el sistema, y el sistema no puede saber a qué le va a
   colgar Bernat un `id` mañana. Se acota a `.c-sala` para no tocar documentos
   que no usen el armazón.

   `scroll-margin-top` no ocupa espacio ni pinta nada: solo le dice al scroll
   dónde tiene que parar. Cero efecto en el layout, cero efecto en el render.
   ─────────────────────────────────────────────────────────────────────────── */
.c-sala [id]{ scroll-margin-top: var(--e-ancla); }


/* ═══════════════════════════════════════════════════════════════════════════
   14 · GANCHOS DEL ARMAZÓN — amplía §11
   ═══════════════════════════════════════════════════════════════════════════

   Misma gramática que §11 (`::before` = materia · `::after` = luz), con UNA
   excepción que hay que leer entera antes de tocar la sala.

   ── LA SALA: DOS CAPAS **FIJAS**, LAS DOS DETRÁS ──────────────────────────
   `.c-sala::before` y `::after` son `position:fixed; inset:0` → miden EL
   VIEWPORT, no la página. Se pintan una vez y no scrollean: así la niebla de la
   cueva, el hollín del taller o el grano del grafito son el aire de la sala y no
   un papel pintado que sube y baja. Las dos van a `z-index:-1`: `::after` se
   pinta encima de `::before` (orden natural) y las dos, debajo del contenido.
     · ¿Dos capas para qué? La de abajo es la MATERIA del mundo (textura, grano,
       roca, fibra); la de arriba es la LUZ del mundo (resplandor de la hoguera,
       haz de la antorcha, viñeta).
     · ¿Quieres una viñeta POR ENCIMA del contenido? Se puede, pero es tu
       decisión y tu responsabilidad: `z-index:1` explícito en tu piel y mide el
       contraste otra vez. Por defecto no, porque una capa encima de todo baja el
       contraste de TODOS los textos de la página a la vez.
     · `isolation:isolate` en `.c-sala` es lo que impide que el `-1` se escape
       detrás del fondo de `<html>` (donde ya vive el fondo infinito de tu época).
     · Ojo: `background-attachment: fixed` en `<html>` y estas capas hacen lo
       mismo. Elige uno de los dos para cada efecto, no los dos.

   ── BARRA, MARCO Y PIE: capas normales (absolutas, a sangre de su caja) ────
   `.c-barra-marca::before` (materia: el vidrio, la losa, la banda de papel) ·
   `::after` (luz: el filo encendido bajo la barra, el reflejo del cristal).
   `.c-marco::before/::after` están libres y son el sitio del "soporte": la hoja
   de papel con sus bordes, la placa, el pergamino. `.c-pie` igual.
   La barra y el pie SÍ cuentan para el ±20% de alto del contrato; la sala no,
   que es fondo.

   ── LO QUE NO ES GANCHO PERO ES TUYO ──────────────────────────────────────
   `--e-marco` `--e-marco-estrecho` `--e-marco-pad` `--e-alto-barra`
   `--e-ancla` `--e-capa-barra` (§1.4). **Si tu barra se sale de su caja** (un
   canto roto, un fleco, una sombra con cuerpo), SUBE `--e-ancla` lo que
   sobresalga: es el único token que el sistema no puede calcular por ti, porque
   solo tu piel sabe cuánto cuelga. Redeclarar el resto es legítimo si tu época
   necesita otro
   ancho de columna, pero piénsalo dos veces: el ancho de lectura no es carácter
   de época, y si cada era mueve el marco, las subpáginas bailan al cambiar.

   `.c-rejilla` NO tiene gancho: es rejilla pura, no tiene materia. Si tu época
   quiere pintar entre las columnas, hazlo en el `.c-marco` o en las propias
   cajas. El movimiento reducido del armazón ya está cubierto por §12 (aplica a
   `*`, `*::before` y `*::after`).
   ═════════════════════════════════════════════════════════════════════════ */

.c-sala::before,
.c-sala::after{
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.c-barra-marca::before, .c-barra-marca::after,
.c-marco::before,       .c-marco::after,
.c-pie::before,         .c-pie::after{
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}
.c-barra-marca::before,
.c-marco::before,
.c-pie::before{ z-index: -1; }

.c-barra-marca::after,
.c-marco::after,
.c-pie::after{ z-index: 1; }


/* ───────────────────────────────────────────────────────────────────────────
   15 · ARMAZÓN EN PANTALLA ESTRECHA
   La barra es lo único que se reorganiza: en el móvil la navegación baja a su
   propia fila y se desliza en horizontal. No se oculta — una navegación que
   desaparece no es responsive, es una navegación menos.
   ─────────────────────────────────────────────────────────────────────────── */
@media (max-width: 760px){
  /* La barra crece: la navegación baja a su propia fila y la barra pasa de
     ~49-56px a ~77-87px según la época. La reserva del ancla (§13.6) tiene que
     crecer con ella o el ancla vuelve a quedar tapada — y aquí el destrozo es
     peor, porque en el móvil la barra ocupa una décima parte de la pantalla.
     Medido en las 5 épocas a 390px y a 760px: la barra más alta es la del
     Hierro (86,3px) y la reserva más corta, la de la Cueva (93,1px). */
  :root{ --e-ancla: calc(var(--e-alto-barra) + 44px); }

  .c-barra-marca{
    padding-block: calc(var(--e-pad-corto) * .38);
    row-gap: calc(var(--e-gap) * .42);
  }
  .c-barra-marca__nav{
    order: 3;
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .c-barra-marca__nav::-webkit-scrollbar{ display: none; }
  .c-barra-marca__nav .c-nav__item{ flex: 0 0 auto; }

  .c-pie{ justify-content: flex-start; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   16 · VARIANTES DEL PILOTO — apéndice de la TERCERA TIRADA (2026-08-12)
   Contrato: design-system/10-contrato-tercera-tirada.md §VARIANTES
   ═══════════════════════════════════════════════════════════════════════════

   QUÉ ES ESTA SECCIÓN
   La GEOMETRÍA de las variantes que las cuatro vistas del piloto (`login.ejs`,
   `modules.ejs`, `module.ejs`, `lesson.ejs` + el partial `academia-top.ejs`)
   necesitan de los 8 componentes del kernel y hoy no existen. Nada más. Ni una
   variante especulativa: cada una de abajo sale de un trozo de marcado REAL, y
   la línea del inventario que la pedía y NO aparece aquí es porque el marcado
   real no la necesita (la lista de descartes está en el informe de la tanda).

   MISMA LEY QUE EL RESTO DEL FICHERO: solo `var(--e-*)`, cero literales de
   color / radio / duración / familia, y selectores de una clase (o dos cuando
   la variante califica a un hijo) para que la piel de época siga ganando.

   ── DE DÓNDE SALE CADA UNA (vista real → variante) ─────────────────────────
   `c-boton--grande` ......... login: `btn btn--flame btn--block btn--lg`
   `c-campo--casilla` ........ login: `.auth__check` («Recordarme»)
   `c-campo--seleccion` ...... academia-top: el `<select>` de «Ver como» (admin)
   `c-cabecera__lead` ........ las CUATRO vistas: el párrafo bajo el titular
   `c-cabecera--linea`
     + `c-cabecera__meta` .... modules y module: `.sec-label` (rótulo + regla +
                               contador a la derecha)
   `c-cabecera--con-acciones`
     + `c-cabecera__acciones`  modules: `.greet` (saludo + 3 cifras a la
                               derecha) · module: `.mat__head` (título + lead +
                               botón «Descargar todo»)
   `c-progreso__etiqueta` .... modules: `.progress__label` («3 de 9 clases
                               completadas»), que ya existe con ese nombre
   `c-instrumento--derecha` .. modules: `.gstat` ×3, alineadas a la derecha
   `c-instrumento__unidad` ... modules: la «m» de `<%= stats.minutes %>m`

   ── APÉNDICE DE PARIDAD (TIRADA 10 · 2026-08-13) ──────────────────────────
   Seis variantes más, y ninguna es nueva tampoco: las seis son cosas que la web
   de hoy YA hace y que el kernel no sabía decir, así que las vistas espejo las
   estaban resolviendo con un `confirm()`, un estilo suelto o una renuncia. La
   fuente de cada una es el punch-list de la noche 2026-08-12 (§Huecos de
   sistema) y el contrato 23 §B.

   `c-boton--peligro` ........ §16.14 · borrar/retirar: 3 sitios del frontal y 8
                               del admin. Va JUNTO a `--fantasma`
   `c-campo--area` ........... §16.15 · el `<textarea>` del foro y del chat
   `c-campo--fichero` ........ §16.16 · la subida del vídeo del testimonio
   `c-campo--en-linea` ....... §16.17 · canje de código, newsletter, buscador
   `c-instrumento--moneda` ... §16.18 · los importes del panel de afiliados
   `c-cabecera--centrada` .... §16.19 · los rótulos de sección de las landings
   (+ §16.20: lo que de todo esto se reorganiza a 390px)

   Y dos retoques que no son variantes sino defectos medidos: `b` se cubre allí
   donde ya se cubría `strong` (§4 y §16.4) y el enlace de la página actual del
   pie estrena piel mínima (§13.5).

   ── LAS DOS TRAMPAS QUE ESTA SECCIÓN TUVO QUE ESQUIVAR ─────────────────────
   1. **Los dos pseudos de `.c-campo` están OCUPADOS** por `vida-campo.css` en
      las cinco épocas (§4.5 los daba por libres: ya no lo están). Por eso ni la
      marca de la casilla ni la flecha del desplegable se dibujan con un pseudo:
      los dos controles vuelven a su widget NATIVO (`appearance: auto`), que
      además hereda `accent-color` y `color-scheme` de la época. Es una escotilla
      deliberada y está medida: un tick dibujado a mano exigía pisar el
      `background` de las cinco pieles (que sí lo declaran) y se habría comido
      el material de cada época en el único sitio donde no aporta nada.
   2. **`.c-cabecera::after` lo usa la época 4** (el filete de latón, que entra
      en la rejilla con `position:static`). Por eso `--linea` dibuja su regla en
      `.c-cabecera__titulo::after` —libre en las cinco— y las dos variantes de
      cabecera colocan a sus hijos con `grid-area` EXPLÍCITA: así el filete de
      la época 4 cae en una fila propia debajo y no se cuela en la fila del
      rótulo. Sin colocación explícita, el auto-placement lo metía en el hueco
      del contador.
   ═════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   16.1 · BOTÓN GRANDE  ·  .c-boton--grande
   El CTA de una puerta (login) y de una landing. Simétrico de `--sm`: solo
   cambia la caja, ni la variante ni la piel. Medido entre épocas: 47,9px
   (Cueva) → 55,2px (Cabina) = +15%, el mismo margen que el botón base.
   ─────────────────────────────────────────────────────────────────────────── */
.c-boton--grande{
  min-height: calc(var(--e-alto-ctrl) * 1.18);
  padding-block: calc(var(--e-pad-corto) * .8);
  padding-inline: calc(var(--e-pad-caja) * 1.5);
  font-size: 16.5px;
}


/* ───────────────────────────────────────────────────────────────────────────
   16.2 · CASILLA  ·  .c-campo--casilla
   Marcado (el del kernel, sin una clase nueva; el orden en el DOM no cambia,
   lo coloca la rejilla):

     <div class="c-campo c-campo--casilla">
       <input class="c-campo__input" type="checkbox" id="r" name="remember">
       <label class="c-campo__etiqueta" for="r">Recordarme</label>
       <p class="c-campo__ayuda">…opcional…</p>
     </div>

   La rejilla de tres filas del campo se convierte en dos columnas: la casilla
   ocupa el área `campo` (que sigue llamándose igual) y la etiqueta el área
   `etiqueta`, a su derecha. La ayuda cruza las dos.

   `appearance: auto` es deliberado (ver trampa 1 de la cabecera): el widget
   nativo dibuja la marca con el contraste que garantiza el sistema operativo y
   `accent-color` lo tiñe con la brasa de la época. Cada `epoca-N.css` retira
   de la casilla la piel del input de texto — que es de OTRO material — en su
   propio apéndice.

   ── QUÉ CONTROLA DE VERDAD EL NAVEGADOR (medido, tirada 10 · 2026-08-13) ───
   El punch-list traía «el filo de la casilla no llega a 3:1 en ninguna época».
   Se fue a comprobar con el widget delante, cambiando una propiedad cada vez y
   mirando el píxel, y esto es lo que hay (Chrome 151, `appearance: auto`):

     `accent-color` ..... pinta SOLO la casilla MARCADA (el relleno y su marca).
                          Sobre la casilla vacía no cambia ni un píxel: se probó
                          con un verde puro y la caja salió idéntica. O sea que
                          «un accent más contrastado por época» no arregla nada
                          del estado que fallaba.
     `border` ........... IGNORADO. Un borde de 3px de verde puro no aparece:
                          el filo del widget lo dibuja el motor y no se toca.
     `color-scheme` ..... redibuja el widget ENTERO. En claro la casilla vacía
                          es una caja blanca —de 4,78 a 17,64 de contraste en la
                          Cueva—, pero es una caja BLANCA en un mundo oscuro, y
                          eso no es un filo mejor: es otra pieza. Solo la usa la
                          é3, y con motivo escrito (allí la casilla cae sobre
                          papel).
     `box-shadow` ....... SÍ pinta, y es el ÚNICO gancho aditivo que queda. No
                          se pelea con el foco, que va por `outline`.

   Con eso, la medida real del filo del widget contra el fondo que tiene al lado
   —que es el criterio de un control, no el del relleno— sale ya por encima del
   3:1 en las cinco ANTES de tocar nada: 3,41 · 5,26 · 18,10 · 5,33 · 5,25 con
   la casilla vacía. El 1,06-1,65 del punch-list es el RELLENO de la casilla
   vacía contra la página, que en un widget nativo transparente es el fondo
   consigo mismo y no mide nada. Con el anillo de material que cada época le
   pone ahora: 4,23 · 5,26 · 18,10 · 5,33 · 5,46.
   El fallo real estaba en otro sitio y era de la é3: su casilla MARCADA se
   pintaba con la rúbrica de la hoja aunque estuviera sobre la mesa — 2,71 ✘
   medido. Arreglado en `epoca-3.css` devolviéndole el contexto de su alrededor.
   Y como margen, cada época le pone su anillo de material con `box-shadow` en
   su apéndice: el filo del sistema alrededor del filo del motor.
   ─────────────────────────────────────────────────────────────────────────── */
.c-campo--casilla{
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas:
    "campo etiqueta"
    "ayuda ayuda";
  align-items: center;
  column-gap: calc(var(--e-gap) * .55);
}
.c-campo--casilla .c-campo__input{
  width: calc(var(--e-alto-ctrl) * .40);
  height: calc(var(--e-alto-ctrl) * .40);
  min-height: 0;
  padding: 0;
  -webkit-appearance: auto;
          appearance: auto;
  accent-color: var(--e-acento);
  cursor: pointer;
}
.c-campo--casilla .c-campo__etiqueta{
  margin-bottom: 0;
  cursor: pointer;
}
.c-campo--casilla .c-campo__ayuda{ grid-area: ayuda; }


/* ───────────────────────────────────────────────────────────────────────────
   16.3 · DESPLEGABLE  ·  .c-campo--seleccion
   Marcado: el mismo del campo, con un `<select class="c-campo__input">`.

   El `<select>` recupera su flecha nativa y conserva el material de su época
   (fondo, filo, radio y letra siguen saliendo de la piel, que no se toca). Se
   le reserva el sitio de la flecha por la derecha para que el texto largo no
   se le meta debajo.
   ─────────────────────────────────────────────────────────────────────────── */
.c-campo--seleccion .c-campo__input{
  -webkit-appearance: auto;
          appearance: auto;
  padding-inline-end: calc(var(--e-pad-caja) * .5);
  cursor: pointer;
}


/* ───────────────────────────────────────────────────────────────────────────
   16.4 · CABECERA · EL LEAD  ·  .c-cabecera__lead
   El párrafo que va bajo el titular. Es la pieza que más falta hacía del
   sistema entero: aparece en las CUATRO vistas del piloto y en 6 + 16 del
   resto de la web. Va después de `__titulo` dentro de `.c-cabecera`.
   ─────────────────────────────────────────────────────────────────────────── */
.c-cabecera__lead{
  margin: 0;
  max-width: 62ch;
  min-width: 0;
  font-family: var(--e-cuerpo);
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--e-tinta-2);
}
/* mismo motivo que en §4: `b` y `strong` son el mismo énfasis para el marcado
   real, así que se cubren juntos. Cero cambios de valor (tirada 10). */
.c-cabecera__lead :is(b, strong){ color: var(--e-tinta); }


/* ───────────────────────────────────────────────────────────────────────────
   16.5 · CABECERA · EL DATO AL MARGEN  ·  .c-cabecera__meta
   El contador de la derecha del rótulo de sección («1 curso», «3 vistas · 6
   por ver»). Misma receta tipográfica que `.c-panel__meta`: mono en
   micro-mayúsculas con cifras tabulares y suelo de tracking — la cabina lo
   tiene negativo y en versalitas eso no se lee.
   ─────────────────────────────────────────────────────────────────────────── */
.c-cabecera__meta{
  font-family: var(--e-mono);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: max(.06em, var(--e-tracking));
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--e-tinta-2);
}


/* ───────────────────────────────────────────────────────────────────────────
   16.6 · CABECERA CON REGLA  ·  .c-cabecera--linea
   El rótulo de sección de `modules` y `module`:

     <header class="c-cabecera c-cabecera--linea">
       <h2 class="c-cabecera__titulo">Las 7 clases</h2>
       <span class="c-cabecera__meta">3 vistas · 4 por ver</span>
     </header>

   NO es el titular de la página: es el rótulo que separa dos zonas, así que el
   título baja a escala de sección. La regla que llena el hueco se dibuja en
   `.c-cabecera__titulo::after` (libre en las cinco épocas) porque el `::after`
   de `.c-cabecera` es del filete de la época 4 — ver trampa 2.
   ─────────────────────────────────────────────────────────────────────────── */
.c-cabecera--linea{
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--e-gap);
}
/* El bloque se cualifica con su propia clase base (`.c-cabecera.c-cabecera--linea`)
   por una razón medida: la ESCALA del rótulo es de la variante, no de la época —
   un rótulo de sección no es el titular de la página—, y dos épocas fijan el
   tamaño del titular en su piel (la 2 a 34px por la caja alta de la Cinzel, la 5
   a 42px). Con un solo nombre de clase, `--linea` medía 54,8px de alto en la
   Cueva y 112,5px en la Cabina: el DOBLE, muy fuera del ±20%. Con las dos, la
   variante fija la escala y la época sigue pudiendo afinarla desde su fichero
   (la 2 lo hace, y con motivo). Es el único sitio del sistema donde base gana a
   una piel, y por eso está escrito aquí. */
.c-cabecera.c-cabecera--linea > .c-cabecera__titulo{
  grid-column: 1;
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: var(--e-gap);
  min-width: 0;
  font-size: clamp(17px, 1.7vw, 21px);
  line-height: 1.2;
  text-wrap: normal;                 /* `balance` no aplica a un contenedor flex */
}
.c-cabecera--linea > .c-cabecera__meta{
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
}
/* la regla: vuelve al flujo (base la deja absoluta a sangre) y estira */
.c-cabecera--linea > .c-cabecera__titulo::after{
  content: "";
  position: static;
  z-index: auto;
  inset: auto;
  flex: 1 1 auto;
  min-width: calc(var(--e-aire) * .5);
  height: max(1px, var(--e-grosor));
  border-radius: 0;
  background: var(--e-linea);
}


/* ───────────────────────────────────────────────────────────────────────────
   16.7 · CABECERA CON ACCIONES  ·  .c-cabecera--con-acciones
   Título (y su lead) a la izquierda, UNA pieza de acciones a la derecha:

     <header class="c-cabecera c-cabecera--con-acciones">
       <h1 class="c-cabecera__titulo">Hola, Bernat</h1>
       <p  class="c-cabecera__lead">Vas por buen camino.</p>
       <div class="c-cabecera__acciones">…botón, o cifras, o lo que sea…</div>
     </header>

   Las tres filas se declaran EXPLÍCITAS (`repeat(3, auto)`) por dos razones que
   no son cosméticas: (a) sin rejilla explícita, `grid-row: 1 / -1` no resuelve
   —la línea −1 se refiere a la rejilla explícita— y el bloque de acciones se
   quedaría clavado en la primera fila en vez de centrarse contra el texto;
   (b) con las áreas fijas, el filete de la época 4 cae en una cuarta fila
   propia y no se mete en el hueco de las acciones. Las filas sin contenido
   miden 0.

   El `row-gap` se pone a 0 y el ritmo vertical vuelve como margen: con tres
   filas declaradas, un `row-gap` dejaría un hueco fantasma cuando falta el
   kicker.

   El bloque de acciones es UNO. Si necesitas dos botones, van dentro de él.
   ─────────────────────────────────────────────────────────────────────────── */
.c-cabecera--con-acciones{
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: repeat(3, auto);
  align-items: center;
  column-gap: var(--e-aire);
  row-gap: 0;
}
.c-cabecera--con-acciones > .c-cabecera__kicker{ grid-area: 1 / 1; }
.c-cabecera--con-acciones > .c-cabecera__titulo{ grid-area: 2 / 1; }
.c-cabecera--con-acciones > .c-cabecera__lead{   grid-area: 3 / 1; }
.c-cabecera--con-acciones > .c-cabecera__titulo:not(:first-child),
.c-cabecera--con-acciones > .c-cabecera__lead{
  margin-top: calc(var(--e-gap) * .42);
}
.c-cabecera__acciones{
  grid-column: 2;
  grid-row: 1 / -1;
  justify-self: end;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-gap);
  min-width: 0;
}


/* ───────────────────────────────────────────────────────────────────────────
   16.8 · PROGRESO · LA ETIQUETA  ·  .c-progreso__etiqueta
   «3 de 9 clases completadas», debajo del carril. Va DENTRO de `.c-progreso`,
   detrás de `.c-progreso__pista`. El nombre existe ya en la web real
   (`.progress__label`), así que la migración es un renombrado.
   ─────────────────────────────────────────────────────────────────────────── */
.c-progreso__etiqueta{
  display: block;
  margin-top: calc(var(--e-gap) * .42);
  font-family: var(--e-mono);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: max(.03em, var(--e-tracking));
  font-variant-numeric: tabular-nums;
  color: var(--e-tinta-2);
}


/* ───────────────────────────────────────────────────────────────────────────
   16.9 · INSTRUMENTO A LA DERECHA  ·  .c-instrumento--derecha
   Las cifras del saludo del dashboard, alineadas al margen derecho. Es
   ALINEACIÓN Y NADA MÁS: la caja, el material y el pilotaje de la época se
   quedan como están —por eso ninguna época necesita piel propia para esta
   variante—. Y es a propósito que no desnuda el instrumento: en la época 3 la
   caja ES la cédula de papel, y quitarla dejaría la cifra de tinta oscura sobre
   la madera del taller (el modo de fallo del protocolo de contexto §4.4).
   ─────────────────────────────────────────────────────────────────────────── */
.c-instrumento--derecha{
  align-items: flex-end;
  text-align: right;
}


/* ───────────────────────────────────────────────────────────────────────────
   16.10 · INSTRUMENTO · LA UNIDAD  ·  .c-instrumento__unidad
   El sufijo pequeño que va PEGADO a la cifra, dentro de `__cifra`: la «m» de
   los minutos, el «/mes» de una cuota. En `em` para que siga a la cifra sea
   cual sea la escala de la época.

     <strong class="c-instrumento__cifra">128<span class="c-instrumento__unidad">m</span></strong>
   ─────────────────────────────────────────────────────────────────────────── */
.c-instrumento__unidad{
  margin-inline-start: .1em;
  font-size: .42em;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--e-tinta-2);
}


/* ───────────────────────────────────────────────────────────────────────────
   16.11 · LAS VARIANTES A 390px
   Las dos cabeceras compuestas son lo único que necesita reorganizarse: a
   pantalla estrecha, el dato y las acciones bajan a su propia fila en vez de
   competir por el ancho con el titular.
   ─────────────────────────────────────────────────────────────────────────── */
@media (max-width: 640px){
  .c-cabecera--linea{ grid-template-columns: minmax(0, 1fr); }
  .c-cabecera--linea > .c-cabecera__meta{
    grid-column: 1;
    grid-row: 2;
    justify-self: start;
  }

  .c-cabecera--con-acciones{
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: repeat(4, auto);
    row-gap: calc(var(--e-gap) * .42);
  }
  .c-cabecera--con-acciones > .c-cabecera__titulo:not(:first-child),
  .c-cabecera--con-acciones > .c-cabecera__lead{ margin-top: 0; }
  .c-cabecera__acciones{
    grid-column: 1;
    grid-row: 4;
    justify-self: start;
  }
}


/* ───────────────────────────────────────────────────────────────────────────
   16.12 · ÉNFASIS EN LÍNEA  ·  .c-enfasis
   Contrato: encargo de cierre de la tercera tirada (2026-08-12). Sustituye a la
   utilidad `flame` de `becama.css`, que el copy del piloto usa en dos vistas:

     <h1 class="c-cabecera__titulo">Hola, <span class="c-enfasis">Bernat</span></h1>
     <h2 …>Deja de ejecutar.<br>Empieza a <span class="c-enfasis">dirigir</span>.</h2>

   LA TESIS: es la palabra que se enciende dentro de una frase. **Geometría cero**
   — ni caja, ni peso, ni familia, ni tamaño: todo eso lo pone la frase que la
   contiene, y por eso la misma clase sirve en un titular de 42px y en un párrafo
   de 15,5px. Aquí solo vive el color; el TRATAMIENTO lo pone cada época.

   POR QUÉ NO ES UNA VARIANTE DE NADA: no cuelga de ninguno de los 21 (puede caer
   dentro de `__titulo`, de `__lead`, de `__cuerpo` o de un `<p>` suelto), así que
   no lleva prefijo de componente. Es la única utilidad del sistema.

   ⚠ LA TRAMPA, Y ES LA DE LA ÉPOCA 3: esta pieza es texto de acento, o sea
   exactamente el modo de fallo nº5 de la skill. `--e-acento` en el Papel es el
   MINIO, que es lo correcto sobre el taller (4.81) y una ruina dentro de una hoja
   (~2:1 sobre el crema). Por eso `epoca-3.css` la pinta con `--e3-rojo`, el token
   de contexto: vale minio en la raíz de la época y rúbrica en cuanto la palabra
   cae dentro de una superficie-hoja. Los DOS frentes están medidos.

   Sin animación propia: una palabra que parpadea dentro de una frase no es
   énfasis, es un anuncio.
   ─────────────────────────────────────────────────────────────────────────── */
.c-enfasis{
  color: var(--e-acento);
}


/* ═══════════════════════════════════════════════════════════════════════════
   16.13 · EL DESPLEGABLE DEL MUNDO  ·  .c-campo--seleccion, mejora progresiva
   Contrato: encargo de Bernat (2026-08-12): «los selectores que se abren son los
   nativos, que hace que se rompa todo».
   ═══════════════════════════════════════════════════════════════════════════

   EL PROBLEMA, EN UNA LÍNEA: hasta aquí `--seleccion` (§16.3) devolvía el
   `<select>` a su widget nativo para heredar la flecha del sistema. El BOTÓN se
   vestía de época sin problema — pero al pulsarlo, el menú que sale lo pinta el
   SISTEMA OPERATIVO: un panel blanco con la tipografía del SO, encima de la
   cueva o del taller. Cinco mundos construidos y un rectángulo de macOS los
   rompe todos.

   LA SOLUCIÓN: `appearance: base-select`. Chrome deja de dibujar el widget y el
   desplegable pasa a ser DOM estilable — `::picker(select)` es la caja, las
   `<option>` son elementos de verdad (con `:hover` y `:checked`), `::picker-icon`
   es la flecha y `option::checkmark` la marca. **Sin una línea de JS y sin tocar
   el marcado**: el mismo `<select class="c-campo__input">` de §16.3.

   ── MEJORA PROGRESIVA, Y ES DELIBERADO ────────────────────────────────────
   Todo esto vive dentro de `@supports (appearance: base-select)`. Donde exista
   (Chrome 135+, que es donde mira Bernat), el desplegable es del mundo. Donde no,
   NO PASA NADA: el `@supports` no aplica, el `appearance: auto` de §16.3 sigue en
   pie y el usuario ve el desplegable nativo — feo, pero **funcional y accesible**.
   Ese es el fallback y está aceptado por contrato, no es una deuda escondida.

   ── LO QUE NO SE TOCA ─────────────────────────────────────────────────────
   El teclado. `base-select` conserva la semántica nativa del `<select>`: flechas
   ↑↓ recorren, Enter/Espacio abren y confirman, Escape cierra, y el foco vuelve
   al botón. No se reimplementa nada — reimplementarlo con JS sería justo la
   forma de romperlo. Verificado con eventos de teclado reales (CDP), no con
   `element.click()`.

   ── LA GRAMÁTICA (esto NO es la de §4.5: el picker no tiene ganchos) ───────
     `::picker(select)` .... la caja abierta = un PANEL del mundo. Lleva su
                             propio `appearance: base-select` para salir del
                             render nativo; sin esa segunda línea, el contenedor
                             sigue siendo del SO aunque el botón ya no lo sea.
     `option` ............... una fila. Es un elemento real: `:hover`, `:checked`,
                             `:focus` y transiciones funcionan.
     `option::checkmark` .... la marca de lo elegido.
     `::picker-icon` ........ la flecha del botón. Gira al abrir.
     `select:open` .......... el botón mientras el picker está desplegado.

   ── LA TRAMPA MEDIDA, Y ES LA DE SIEMPRE: LA ÉPOCA 3 ──────────────────────
   El picker se pinta con `--e-sup`, y en el Papel `--e-sup` **ES LA HOJA**. O
   sea: el desplegable abierto es una superficie de papel NUEVA, y el §4.4 lo dice
   sin ambigüedad — cualquier superficie de papel nueva REDECLARA el protocolo de
   contexto. Sin eso, base pinta las `option` con `--e-tinta` (la crema del
   taller) sobre el crema de la hoja: **1,04:1 medido antes del arreglo**, texto
   invisible. `epoca-3.css` redeclara los `--e3-*` en el propio `::picker(select)`
   y las opciones se vuelven tinta solas.

   ── LEY DEL CALOR EN UNA LISTA ────────────────────────────────────────────
   La fila no cambia de color al pasar por encima: **se calienta el fondo** y la
   letra se queda quieta (§4.2 — el color del texto ni se retrasa ni se
   interpola). Entrada `var(--e-vel)`, salida ×3,5.
   ═════════════════════════════════════════════════════════════════════════ */

@supports (appearance: base-select){

  /* — EL BOTÓN — la misma caja de §16.3, ahora contenedor de verdad — */
  .c-campo--seleccion .c-campo__input{
    -webkit-appearance: base-select;
            appearance: base-select;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: calc(var(--e-gap) * .5);
    text-align: start;
    /* la flecha ya es un hijo real: el hueco que le reservaba §16.3 sobra */
    padding-inline-end: calc(var(--e-pad-caja) * .72);
  }

  /* — LA FLECHA — gira al abrir. Es lo único que se mueve del botón — */
  .c-campo--seleccion .c-campo__input::picker-icon{
    color: var(--e-tinta-2);
    transition: rotate var(--e-vel) var(--e-curva);
  }
  .c-campo--seleccion .c-campo__input:open::picker-icon{ rotate: 180deg; }

  /* — EL PICKER — la caja abierta: un panel del mundo —
     `min-width: anchor-size(width)` lo ancla al ancho del botón: la lista nunca
     sale más estrecha que el control que la abre. `max-height` + scroll para que
     una lista larga no se salga de la pantalla. */
  .c-campo--seleccion .c-campo__input::picker(select){
    -webkit-appearance: base-select;
            appearance: base-select;
    box-sizing: border-box;
    min-width: anchor-size(width);
    max-height: 60vh;
    overflow-y: auto;
    margin-block-start: calc(var(--e-gap) * .34);
    padding: calc(var(--e-pad-corto) * .34);
    border: var(--e-grosor) solid var(--e-linea);
    border-radius: var(--e-radio);
    background: var(--e-sup);
    color: var(--e-tinta);
  }

  /* — LA FILA — */
  .c-campo--seleccion .c-campo__input option{
    display: flex;
    align-items: center;
    gap: calc(var(--e-gap) * .5);
    min-height: calc(var(--e-alto-ctrl) * .72);
    padding-block: calc(var(--e-pad-corto) * .3);
    padding-inline: calc(var(--e-pad-caja) * .5);
    border-radius: calc(var(--e-radio) * .55);
    background: none;
    color: var(--e-tinta);
    font-family: var(--e-cuerpo);
    font-size: 14.5px;
    line-height: 1.3;
    cursor: pointer;
    /* ley del calor: sale despacio. Y SOLO el fondo — el color del texto no se
       interpola nunca (§4.2), por eso no está en la lista. */
    transition: background calc(var(--e-vel) * 3.5) linear;
  }
  .c-campo--seleccion .c-campo__input option:hover,
  .c-campo--seleccion .c-campo__input option:focus{
    background: color-mix(in oklab, var(--e-acento) 16%, var(--e-nada));
    transition-duration: var(--e-vel);          /* entra rápido */
  }
  .c-campo--seleccion .c-campo__input option:checked{
    background: color-mix(in oklab, var(--e-acento) 10%, var(--e-nada));
  }

  /* — LA MARCA DE LO ELEGIDO — al margen derecho, del color de la época — */
  .c-campo--seleccion .c-campo__input option::checkmark{
    order: 1;
    margin-inline-start: auto;
    color: var(--e-acento);
  }

  /* — el foco de teclado dentro de la lista, con el mismo anillo del sistema — */
  .c-campo--seleccion .c-campo__input option:focus-visible{
    outline: max(2px, var(--e-grosor)) solid var(--e-acento);
    outline-offset: calc(var(--e-grosor) * -1);
  }
}

@supports (appearance: base-select){
  @media (prefers-reduced-motion: reduce){
    .c-campo--seleccion .c-campo__input::picker-icon{ transition: none; }
    .c-campo--seleccion .c-campo__input option{ transition: none; }
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   16.14 · BOTÓN DE PELIGRO  ·  .c-boton--peligro
   Contrato: design-system/23-contrato-tirada-10-kernel.md §B.6 (PARIDAD)
   ═══════════════════════════════════════════════════════════════════════════

   DE DÓNDE SALE: 11 sitios de la web real (3 del frontal + 8 del admin) tienen
   un botón de borrar o de retirar — retirar un testimonio, borrar un hilo, un
   mensaje, un canal, una campaña. Hoy todos son `--fantasma --sm` y el aviso lo
   pone `confirm()`. O sea: la única diferencia entre «Ver» y «Borrar para
   siempre» estaba en el texto.

   LA TESIS, Y ES LO QUE LA SEPARA DE UN SEGUNDO ACENTO:
     NO es otro color de marca. Es EL BOTÓN FANTASMA CON EL AVISO DEL MATERIAL.

   Por eso el marcado lo pone JUNTO a `--fantasma`, no en su lugar:

     <button class="c-boton c-boton--fantasma c-boton--peligro c-boton--sm">Retirar</button>

   Así el material entero —la textura de la pared, el relieve de la piedra, el
   papel del taller, la chapa, el cristal— y su capa de vida siguen saliendo de
   `--fantasma` en las cinco épocas, sin duplicar ni una receta: lo único que
   `--peligro` cambia es el FILO y la TINTA. Un botón que estrena material sería
   una pieza nueva; esto es una advertencia sobre la pieza que ya hay.
   (Sin `--fantasma` tampoco se rompe: hereda de aquí filo y tinta y se ve como
   lo que es. Pero el sitio del que sale la web real lleva los dos.)

   ── EL MECANISMO: EL CALOR DE ESTE BOTÓN ES OTRO ──────────────────────────
   «El hover se calienta hacia el peligro, no hacia la brasa» no se consigue
   repintando a mano las cinco vidas —vive en `vida-boton.css`, que se carga
   DESPUÉS—: se consigue cambiándole a ESTE botón lo que para él significa
   «acento». Los tres tokens de calor se redeclaran EN LA PIEZA, y todo lo que
   cuelga de ellos (el resplandor del pseudo de la vida, el anillo de foco de
   base §2 y de las pieles, el halo) se vuelve aviso solo, en las cinco épocas.
   Es el mismo mecanismo de herencia del protocolo `--e3-*` de la época 3, y no
   choca con la regla de no redeclarar tokens dentro de un contenedor: esa habla
   de las escalas DERIVADAS de `--e-aire` (§1.2), que se resolvieron ya en
   `<html>`; los colores se resuelven donde se usan.

   ── CONTRASTE ────────────────────────────────────────────────────────────
   El rojo lo pone cada época en `--e-peligro` (§1.3). Los cinco están medidos
   como TEXTO sobre la superficie del botón, y ninguno es un rojo puro: los
   rojos saturados no llegan a 4.5 sobre fondos oscuros y por eso cada época ya
   tenía el suyo aclarado (la é1 lo dice en el nombre: «tierra quemada ACLARADA
   para cumplir contraste»).
   ─────────────────────────────────────────────────────────────────────────── */
.c-boton--peligro{
  /* el calor de ESTE botón: aviso, no brasa */
  --e-acento:        var(--e-peligro);
  --e-acento-nucleo: color-mix(in oklab, var(--e-peligro) 62%, var(--e-tinta));
  --e-halo:          color-mix(in srgb, var(--e-peligro) 40%, transparent);

  border-color: color-mix(in oklab, var(--e-peligro) 52%, var(--e-linea));
  color: var(--e-peligro);
}
.c-boton--peligro:hover{
  border-color: var(--e-peligro);
  background-color: color-mix(in oklab, var(--e-peligro) 12%, var(--e-nada));
}
.c-boton--peligro:focus-visible{ outline-color: var(--e-peligro); }


/* ───────────────────────────────────────────────────────────────────────────
   16.15 · CAMPO · EL ÁREA  ·  .c-campo--area
   Contrato: §B.7. El `<textarea>` del foro, del chat y de los formularios de
   contacto. Marcado: el del campo, con un `<textarea class="c-campo__input">`.

   No estrena piel: HEREDA TODA la del input de texto de su época (fondo, filo,
   radio, letra, foco, error) porque lleva su misma clase. Aquí solo vive lo que
   un input de una línea no puede tener: alto de partida, aire vertical de
   párrafo y el tirador.

   `resize: vertical` y no `both`: a lo ancho el campo pertenece a la rejilla de
   su formulario, y dejar que el usuario lo estire rompe la columna. Medido
   entre épocas: 126px (Cueva) → 145px (Cabina) = +15%, dentro del ±20%.
   ─────────────────────────────────────────────────────────────────────────── */
.c-campo--area .c-campo__input{
  min-height: calc(var(--e-alto-ctrl) * 3.1);
  padding-block: calc(var(--e-pad-corto) * .72);
  line-height: 1.55;
  resize: vertical;
}


/* ───────────────────────────────────────────────────────────────────────────
   16.16 · CAMPO · EL FICHERO  ·  .c-campo--fichero
   Contrato: §B.8. La subida del vídeo del testimonio. Marcado: el del campo,
   con un `<input class="c-campo__input" type="file">`.

   El control tiene DOS partes y el navegador las pinta las dos: un botón y el
   nombre del fichero elegido. `::file-selector-button` es el único gancho que
   da el motor para la primera, y se viste como lo que es —un botón fantasma
   pequeño del material— con los mismos tokens que `.c-boton--fantasma` y
   `.c-boton--sm`: no se redibuja nada, se repite la receta que ya existe
   porque un pseudo-elemento no puede llevar una clase.

   El nombre del fichero es texto secundario y se pinta como tal. La caja del
   input baja su relleno para que el botón no la reviente: el alto lo manda
   ahora el botón de dentro, no el `min-height` heredado.
   ─────────────────────────────────────────────────────────────────────────── */
.c-campo--fichero .c-campo__input{
  padding-block: calc(var(--e-pad-corto) * .3);
  padding-inline: calc(var(--e-pad-caja) * .34);
  color: var(--e-tinta-2);
  font-size: 13.5px;
  line-height: 1.5;
  cursor: pointer;
}
.c-campo--fichero .c-campo__input::file-selector-button{
  min-height: calc(var(--e-alto-ctrl) * .72);
  margin-inline-end: calc(var(--e-gap) * .55);
  padding-block: calc(var(--e-pad-corto) * .34);
  padding-inline: calc(var(--e-pad-caja) * .6);

  border: var(--e-grosor) solid var(--e-linea);
  border-radius: var(--e-radio);
  background: none;
  color: var(--e-tinta);

  font-family: var(--e-display);
  font-weight: var(--e-peso-display);
  font-size: 13px;
  line-height: 1.15;
  letter-spacing: var(--e-tracking);
  cursor: pointer;
  transition:
    background   var(--e-vel) linear,
    border-color var(--e-vel) linear;
}
.c-campo--fichero .c-campo__input::file-selector-button:hover{
  background: color-mix(in oklab, var(--e-tinta) 8%, var(--e-nada));
  border-color: color-mix(in oklab, var(--e-tinta) 40%, var(--e-linea));
}
/* §12 congela el movimiento con `*, *::before, *::after`, y ESTE pseudo no está
   en esa lista: es el único de la tanda que trae transición propia, así que se
   apaga a mano. Estado final, quieto, sin perder nada. */
@media (prefers-reduced-motion: reduce){
  .c-campo--fichero .c-campo__input::file-selector-button{ transition: none; }
}


/* ───────────────────────────────────────────────────────────────────────────
   16.17 · CAMPO EN LÍNEA  ·  .c-campo--en-linea
   Contrato: §B.9. El canje de un código, el alta en la newsletter, un buscador:
   un campo y su botón en la MISMA fila. Marcado congelado — el botón es un hijo
   más del campo, entre el input y la ayuda:

     <div class="c-campo c-campo--en-linea">
       <label class="c-campo__etiqueta" for="k">Código</label>
       <input class="c-campo__input" id="k" type="text">
       <button class="c-boton c-boton--brasa">Canjear</button>
       <p class="c-campo__ayuda">Se aplica al total.</p>
     </div>

   GEOMETRÍA Y NADA MÁS: ninguna época necesita piel para esta variante, porque
   no hay material nuevo — hay un campo y un botón, cada uno con el suyo. La
   rejilla de tres filas del campo pasa a dos columnas: el campo crece
   (`minmax(0,1fr)`), el botón NO (`auto`), y la etiqueta y la ayuda cruzan las
   dos. El `align-items: stretch` de la rejilla es el que iguala los altos sin
   que nadie tenga que declararlos.

   A 390 se apila (§16.20): un campo y un botón compitiendo por 350px dejan al
   botón en dos líneas o al campo en cuatro caracteres.
   ─────────────────────────────────────────────────────────────────────────── */
.c-campo--en-linea{
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "etiqueta etiqueta"
    "campo    accion"
    "ayuda    ayuda";
  column-gap: calc(var(--e-gap) * .5);
}
.c-campo--en-linea > .c-boton{ grid-area: accion; }


/* ───────────────────────────────────────────────────────────────────────────
   16.18 · INSTRUMENTO · LA MONEDA  ·  .c-instrumento--moneda
   Contrato: §B.10. Los importes del panel de afiliados: comisiones, retenciones
   y devoluciones en la misma rejilla. Marcado: el del instrumento, con el
   ESTADO en la pieza (no en la cifra: el estado describe el dato, y la cifra es
   solo donde se ve).

     <article class="c-instrumento c-instrumento--moneda is-positiva">
       <strong class="c-instrumento__cifra">+248,50<span class="c-instrumento__unidad">€</span></strong>
       <span class="c-instrumento__etiqueta">COMISIONES DEL MES</span>
     </article>

   Estados: `is-positiva` (entra) · `is-negativa` (sale) · sin clase (neutra, la
   cifra normal de la época). Los pone el servidor y no se quitan.

   EL SIGNO NO ES SOLO COLOR — el `+` y el `−` van en el texto, que es lo que
   lee quien no distingue el verde del rojo; el color subraya, no informa solo.
   `tabular-nums` ya viene de base §7: una columna de importes tiene que cuadrar
   por la coma.

   La unidad (el €) se queda en `--e-tinta-2` a propósito: lo que cambia de
   color es la CIFRA. Y la etiqueta también: si se tiñera todo, la tarjeta
   entera sería una alarma.
   ─────────────────────────────────────────────────────────────────────────── */
.c-instrumento--moneda.is-positiva .c-instrumento__cifra{ color: var(--e-ok); }
.c-instrumento--moneda.is-negativa .c-instrumento__cifra{ color: var(--e-peligro); }


/* ───────────────────────────────────────────────────────────────────────────
   16.19 · CABECERA CENTRADA  ·  .c-cabecera--centrada
   Contrato: §B.11. Los rótulos de sección de las landings, que en la web vieja
   iban centrados y en el espejo se quedaron a la izquierda (salvo en la é2, que
   los centra por ley axial).

   GEOMETRÍA PURA, y por eso no lleva piel: `justify-items` centra las CAJAS de
   los hijos dentro de la rejilla y `text-align` centra sus líneas. Hacen falta
   los dos: sin el primero, el lead se queda con su caja de 62ch pegada a la
   izquierda y solo se centra su texto dentro de ella.

   ⚠ HERENCIA CON LA ÉPOCA 2: la Piedra ya declara `text-align: center` en toda
   `.c-cabecera` (su ley axial, §9 de esa hoja) con especificidad mayor que
   ésta. No hay pelea: el valor es el MISMO, así que esta variante no cambia
   nada en la é2 salvo el centrado de las cajas, que es lo que allí faltaba.
   Comprobado en el banco: en la é2 el antes y el después de `--centrada` solo
   se diferencian en el lead, que era lo que se descolgaba.

   NO se combina con `--linea` ni con `--con-acciones`: esas dos declaran su
   propia rejilla de columnas y el centrado no tendría dónde ocurrir.
   ─────────────────────────────────────────────────────────────────────────── */
.c-cabecera--centrada{
  justify-items: center;
  text-align: center;
}


/* ───────────────────────────────────────────────────────────────────────────
   16.20 · LAS VARIANTES DE PARIDAD A 390px
   Hermana de §16.11: allí se reorganizan las dos cabeceras compuestas, aquí lo
   único de la tanda de paridad que no cabe en una pantalla estrecha.

   El campo en línea se apila. El hueco entre el campo y el botón vuelve como
   margen y no como `row-gap`, por el mismo motivo que en §16.7: la rejilla del
   campo tiene filas que pueden venir vacías (sin etiqueta, sin ayuda) y un
   `row-gap` dejaría el hueco igual.
   ─────────────────────────────────────────────────────────────────────────── */
@media (max-width: 640px){
  .c-campo--en-linea{
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "etiqueta"
      "campo"
      "accion"
      "ayuda";
  }
  .c-campo--en-linea > .c-boton{ margin-top: calc(var(--e-gap) * .42); }
}
