/* Nada Menos — tokens v5.0 (Quipu 26Q4)
   Fuente de verdad: DESIGN.md de este repo, que desde el 2026-09-02 consume
   los parámetros del sistema Quipu 26Q4 de Curaca (repo `quipu`,
   `tokens/tokens.d1a757c9.css` y `decisiones/2026-09-02-modo-claro-piedra-y-franjas.md`).
   Tipografías: Outfit y Bitter, servidas desde `marca/fuentes/` (ver el
   bloque de @font-face más abajo). Nada se pide a fonts.googleapis.com.

   Arquitectura: primitivas (--nm-p-*) con los hex y semánticos (--nm-*)
   con el rol. Los componentes solo usan semánticos. El MODO CLARO sigue
   siendo el principal de Nada Menos (bare :root) y el oscuro se activa por
   prefers-color-scheme o con data-theme="oscuro".

   Lo que cambió con 26Q4 — «índigo de noche, piedra de día»:
     · El neutral es FRÍO en los dos modos. El crema (#FBF9F4 / #F6F2EA)
       dejó de ser fondo: crema + maíz tostado es cálido sobre cálido, el
       nudo se apaga y la página se ve como cualquier generador
       (quipu/errores/color.md #10). El claro vive en piedra, el oscuro en
       índigo profundo. La única nota cálida de la pantalla es el maíz.
     · Dos oficios para el oro, con token propio cada uno: --nm-acento es
       el oro de TEXTO y FOCO (ocre en claro, 5.39:1; maíz en oscuro) y
       --nm-nudo es el RELLENO del nudo focal (ámbar en claro, maíz en
       oscuro). Un nudo relleno de ocre se veía marrón; el ámbar es el
       mismo pigmento con luz.
     · Franjas: cada sección mayor es un colgante con fondo propio (base,
       papel, índigo). El índigo abre y cierra la página —hero y pie— y en
       oscuro no invierte: sube un nivel de superficie.

   Lo que NO cambió: la acción es TINTA (botón primario profundo en claro,
   hueso en oscuro), pill en botones y chips, Outfit + Bitter, el verde
   fuera del sistema, y el presupuesto del motivo. */

/* ── Las dos familias, servidas desde el repo ──────────────────────────
   Outfit y Bitter viven en `marca/fuentes/` y se sirven bajo `/marca/`,
   como el resto de los activos de marca: una sola copia, versionada acá,
   sin pedirle nada a fonts.googleapis.com.

   Por qué no Google Fonts: la web tiene que poder cargar sin un tercero
   —dentro del cascarón de Capacitor no hay red garantizada al arrancar, y
   `privacidad.html` promete que no hay terceros—, y dos handshakes contra
   otro dominio antes del primer texto cuestan más que los 83 kB de estos
   cuatro archivos.

   Solo latín y latín extendido: los subconjuntos cirílico y vietnamita que
   Google sirve no le hacen falta a un comparador de precios peruano.
   `font-display: swap` para que el texto se lea desde el primer pintado con
   la fuente de respaldo (system-ui / Georgia) y salte a la buena al llegar.

   Outfit es variable (400–700 en un solo archivo, `font-weight: 400 700`);
   Bitter va solo en regular, que es lo único que DESIGN.md le permite.
   Procedencia y cómo volver a bajarlas: `marca/fuentes/LEEME.md`. */

@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/marca/fuentes/outfit-400-700-latin.6c18d579.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/marca/fuentes/outfit-400-700-latin-ext.0f53d1c0.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Bitter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/marca/fuentes/bitter-400-latin.a9960fdb.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bitter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/marca/fuentes/bitter-400-latin-ext.9412cae5.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ── Primitivas ───────────────────────────────────────────── */
  /* Escala nocturna: índigo profundo → noche → cerro → cumbre */
  --nm-p-profundo:   #0D1120;
  --nm-p-noche:      #141A2E;
  --nm-p-cerro:      #1A2138;
  --nm-p-cumbre:     #202844;

  /* Escala diurna: piedra (neutral frío de la familia del índigo) →
     caliza → cal. La elevación sube hacia el blanco. */
  --nm-p-piedra:     #E9EBF0;
  --nm-p-caliza:     #F4F5F8;
  --nm-p-cal:        #FFFFFF;

  /* Acción: el eje 227° del neutral, saturado. No es un tercer tono del
     sistema, es el propio con el volumen subido (Quipu 3.3.0,
     decisiones/2026-09-11-acento-de-accion.md). */
  --nm-p-anil:       #15245B;  /* relleno de acción en claro; texto hueso, 13.19:1 */
  --nm-p-anil-hover: #1B2E74;
  --nm-p-helada:     #BFC7E3;  /* relleno de acción en oscuro y en franja; texto profundo, 11.17:1 */
  --nm-p-helada-hover: #D4D9ED;

  /* Texto */
  --nm-p-hueso:      #F5F3EE;  /* texto principal sobre oscuro y en franjas índigo; ya no es fondo */
  --nm-p-niebla:     #C5CBD8;  /* texto secundario sobre oscuro */
  --nm-p-pizarra-osc:#8E97AC;  /* texto terciario sobre oscuro */
  --nm-p-grafito:    #3E4453;  /* texto secundario sobre claro */
  --nm-p-pizarra:    #5F6880;  /* texto terciario sobre claro (4.66:1 sobre piedra) */

  /* Líneas */
  --nm-p-linea-clr:        #D0D4DE;
  --nm-p-linea-fuerte-clr: #B7BDCB;
  --nm-p-linea-osc:        #252D45;
  --nm-p-linea-fuerte-osc: #333D5A;
  --nm-p-linea-franja-osc: #2A3350;  /* filetes dentro de la franja noche */
  --nm-p-linea-franja-fuerte-osc: #3A4565;
  --nm-p-franja-superficie-clr: #161C31;  /* tarjeta dentro de la franja índigo en claro */

  /* Maíz — la única nota cálida del sistema */
  --nm-p-maiz:       #F0C45E;  /* acento y nudo en oscuro; nudo en franjas índigo */
  --nm-p-maiz-palido:#F5D488;  /* hover sobre oscuro */
  --nm-p-ocre:       #7A5912;  /* acento de texto y foco en claro (5.39:1 sobre piedra) */
  --nm-p-ocre-hover: #5F4510;
  --nm-p-ambar:      #A97F1B;  /* relleno del nudo focal en claro (3:1 sobre piedra) */

  /* Error: solo validación de formulario. No hay token de éxito en Nada
     Menos: la validación positiva se resuelve con tinta y un icono. */
  --nm-p-error-clr:  #A63E35;
  --nm-p-error-osc:  #E07A6E;

  /* ── Semánticos: modo claro (principal) ──────────────────── */
  --nm-fondo:        var(--nm-p-piedra);
  --nm-superficie-1: var(--nm-p-caliza);   /* tarjetas */
  --nm-superficie-2: var(--nm-p-cal);      /* anidado, hover, popovers */
  --nm-superficie-3: var(--nm-p-cal);      /* en claro Cal es el techo: la diferencia la hace la sombra */

  --nm-texto:        var(--nm-p-profundo);
  --nm-texto-2:      var(--nm-p-grafito);
  --nm-texto-3:      var(--nm-p-pizarra);

  --nm-borde-sutil:  var(--nm-p-linea-clr);
  --nm-borde:        var(--nm-p-linea-clr);
  --nm-borde-fuerte: var(--nm-p-linea-fuerte-clr);
  --nm-borde-tarjeta: var(--nm-p-linea-clr);

  /* La acción tiene color propio desde Quipu 3.3.0: añil en claro, helada en
     oscuro y en franja. No es un tercer tono del sistema, es el eje 227° del
     neutral saturado. El oro queda libre para el dato, que es su único oficio. */
  --nm-primario:       var(--nm-p-anil);
  --nm-primario-tinta: var(--nm-p-hueso);
  --nm-primario-hover: var(--nm-p-anil-hover);

  /* Oro de texto y foco */
  --nm-acento:       var(--nm-p-ocre);
  --nm-acento-hover: var(--nm-p-ocre-hover);
  --nm-acento-suave: rgba(122, 89, 18, .10);
  /* Oro de relleno: el nudo focal */
  --nm-nudo:         var(--nm-p-ambar);

  --nm-campo:        var(--nm-p-cal);   /* campo hundido: en claro sube a Cal */

  --nm-error:        var(--nm-p-error-clr);
  --nm-foco:         var(--nm-p-ocre);

  /* Sombras tenues, frías como el neutral */
  --nm-sombra-1:     0 1px 2px rgba(13, 17, 32, .06);
  --nm-sombra-2:     0 12px 32px rgba(13, 17, 32, .08);

  /* Velo de la cabecera pegajosa: el fondo de página al 90%. */
  --nm-velo-nav:     rgba(233, 235, 240, .90);

  /* Velos de las capas que se abren encima de la página (`hoja`, `.dialogo`,
     el visor de foto). Van acá, como --nm-velo-nav, porque tokens.css es la
     única capa donde el sistema admite literales; en estilo.css el velo se
     pide siempre por token, así cambia con el modo como cualquier superficie.
     El pigmento es profundo puro en los dos modos —cero tinte de acento, que
     es regla dura del oscuro— y en oscuro sube de alfa: debajo ya hay índigo,
     y un .45 sobre profundo no lee como capa. */
  --nm-velo:         rgba(13, 17, 32, .45);
  --nm-velo-foto:    rgba(13, 17, 32, .85);

  /* ── Franjas (DESIGN, Layout & Spacing) ────────────────────
     papel: la banda de trabajo, un peldaño sobre el fondo, con filete
     arriba y abajo. índigo: la franja invertida que abre y cierra la
     página (hero y pie); en oscuro no invierte, sube a noche. */
  --nm-banda:        var(--nm-p-caliza);
  --nm-banda-sup-1:  var(--nm-p-cal);
  --nm-banda-sup-2:  var(--nm-p-cal);
  --nm-banda-linea:  var(--nm-p-linea-clr);

  --nm-franja:            var(--nm-p-profundo);
  --nm-franja-texto:      var(--nm-p-hueso);
  --nm-franja-texto-2:    var(--nm-p-niebla);
  --nm-franja-texto-3:    var(--nm-p-pizarra-osc);
  --nm-franja-linea:      var(--nm-p-linea-osc);
  --nm-franja-linea-fuerte: var(--nm-p-linea-fuerte-osc);
  --nm-franja-superficie: var(--nm-p-franja-superficie-clr);
  --nm-franja-acento:     var(--nm-p-maiz);
  --nm-franja-nudo:       var(--nm-p-maiz);
  --nm-franja-boton:      var(--nm-p-helada);
  --nm-franja-boton-tinta: var(--nm-p-profundo);

  /* ── Tipografía ──────────────────────────────────────────── */
  /* Dos familias (cierre 2026-08-23): Outfit hace TODO — interfaz, cuerpo,
     botones, etiquetas, wordmark — y Bitter es el acento serif, solo
     regular, una vez por vista: el titular del hero y el número del dato
     ganador. Ningún componente nombra la familia: siempre vía token. */
  --nm-cuerpo: 'Outfit', system-ui, sans-serif;
  --nm-serif:  'Bitter', Georgia, serif;

  --nm-d1: 52px;  --nm-d1-tracking: -0.02em;   /* peso 700 */
  --nm-d2: 36px;  --nm-d2-tracking: -0.02em;   /* peso 700 */
  --nm-d3: 26px;  --nm-d3-tracking: -0.015em;  /* peso 700 */
  --nm-d4: 21px;  --nm-d4-tracking: -0.01em;   /* peso 700, título de fila */
  /* El ahorro, el héroe: Bitter regular, sin tracking negativo. */
  --nm-precio: 44px;  --nm-precio-tracking: 0;
  --nm-b1: 17px;
  --nm-b2: 15px;
  --nm-b3: 13px;
  --nm-l1: 12px;  --nm-l1-tracking: 0.09em;
  --nm-lh-display: 1.15;
  --nm-lh-cuerpo:  1.6;
  --nm-lh-ui:      1.45;
  --nm-medida:     66ch;

  /* ── Espaciado (base 4) ──────────────────────────────────── */
  --nm-esp-1: 4px;   --nm-esp-2: 8px;   --nm-esp-3: 12px;
  --nm-esp-4: 16px;  --nm-esp-5: 24px;  --nm-esp-6: 32px;
  --nm-esp-7: 48px;  --nm-esp-8: 64px;

  /* ── Radios ──────────────────────────────────────────────── */
  /* Más redonda que Curaca a propósito: botones y chips son pill. */
  --nm-radio-sm:   4px;
  --nm-radio-md:   8px;    /* inputs */
  --nm-radio-lg:   12px;   /* tarjetas */
  --nm-radio-xl:   16px;   /* modales */
  --nm-radio-full: 999px;  /* botones, chips, contadores */

  /* ── Motion ──────────────────────────────────────────────── */
  --nm-mov-micro:   120ms;
  --nm-mov-base:    200ms;
  --nm-mov-entrada: 320ms;
  --nm-curva-salida: cubic-bezier(0.2, 0, 0, 1);
  --nm-curva-suave:  cubic-bezier(0.4, 0, 0.2, 1);

  color-scheme: light;
}

/* ── Semánticos: modo oscuro ─────────────────────────────────
   Por preferencia del sistema, o forzado con data-theme="oscuro". La paleta
   va escrita dos veces porque CSS no sabe componer «media query O
   atributo». Superficies índigo neutro-frío con CERO tinte de acento. */
[data-theme="oscuro"] { color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="claro"]) { color-scheme: dark; }
}

:root[data-theme="oscuro"] {
  --nm-fondo:        var(--nm-p-profundo);
  --nm-superficie-1: var(--nm-p-noche);
  --nm-superficie-2: var(--nm-p-cerro);
  --nm-superficie-3: var(--nm-p-cumbre);
  --nm-texto:        var(--nm-p-hueso);
  --nm-texto-2:      var(--nm-p-niebla);
  --nm-texto-3:      var(--nm-p-pizarra-osc);
  --nm-borde-sutil:  var(--nm-p-linea-osc);
  --nm-borde:        var(--nm-p-linea-osc);
  --nm-borde-fuerte: var(--nm-p-linea-fuerte-osc);
  --nm-borde-tarjeta: var(--nm-p-linea-osc);
  --nm-primario:       var(--nm-p-helada);
  --nm-primario-tinta: var(--nm-p-profundo);
  --nm-primario-hover: var(--nm-p-helada-hover);
  --nm-acento:       var(--nm-p-maiz);
  --nm-acento-hover: var(--nm-p-maiz-palido);
  --nm-acento-suave: rgba(240, 196, 94, .12);
  --nm-nudo:         var(--nm-p-maiz);
  --nm-campo:        var(--nm-p-profundo);
  --nm-error:        var(--nm-p-error-osc);
  --nm-foco:         var(--nm-p-maiz);
  --nm-sombra-1:     none;
  --nm-sombra-2:     0 8px 28px rgba(0, 0, 0, .45);
  --nm-velo-nav:     rgba(13, 17, 32, .90);
  --nm-velo:         rgba(13, 17, 32, .72);
  --nm-velo-foto:    rgba(13, 17, 32, .92);
  --nm-banda:        var(--nm-p-noche);
  --nm-banda-sup-1:  var(--nm-p-cerro);
  --nm-banda-sup-2:  var(--nm-p-cumbre);
  --nm-banda-linea:  var(--nm-p-linea-franja-osc);
  --nm-franja:            var(--nm-p-noche);
  --nm-franja-linea:      var(--nm-p-linea-franja-osc);
  --nm-franja-linea-fuerte: var(--nm-p-linea-franja-fuerte-osc);
  --nm-franja-superficie: var(--nm-p-cerro);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="claro"]) {
    --nm-fondo:        var(--nm-p-profundo);
    --nm-superficie-1: var(--nm-p-noche);
    --nm-superficie-2: var(--nm-p-cerro);
    --nm-superficie-3: var(--nm-p-cumbre);
    --nm-texto:        var(--nm-p-hueso);
    --nm-texto-2:      var(--nm-p-niebla);
    --nm-texto-3:      var(--nm-p-pizarra-osc);
    --nm-borde-sutil:  var(--nm-p-linea-osc);
    --nm-borde:        var(--nm-p-linea-osc);
    --nm-borde-fuerte: var(--nm-p-linea-fuerte-osc);
    --nm-borde-tarjeta: var(--nm-p-linea-osc);
    --nm-primario:       var(--nm-p-helada);
    --nm-primario-tinta: var(--nm-p-profundo);
    --nm-primario-hover: var(--nm-p-helada-hover);
    --nm-acento:       var(--nm-p-maiz);
    --nm-acento-hover: var(--nm-p-maiz-palido);
    --nm-acento-suave: rgba(240, 196, 94, .12);
    --nm-nudo:         var(--nm-p-maiz);
    --nm-campo:        var(--nm-p-profundo);
    --nm-error:        var(--nm-p-error-osc);
    --nm-foco:         var(--nm-p-maiz);
    --nm-sombra-1:     none;
    --nm-sombra-2:     0 8px 28px rgba(0, 0, 0, .45);
    --nm-velo-nav:     rgba(13, 17, 32, .90);
    --nm-velo:         rgba(13, 17, 32, .72);
    --nm-velo-foto:    rgba(13, 17, 32, .92);
    --nm-banda:        var(--nm-p-noche);
    --nm-banda-sup-1:  var(--nm-p-cerro);
    --nm-banda-sup-2:  var(--nm-p-cumbre);
    --nm-banda-linea:  var(--nm-p-linea-franja-osc);
    --nm-franja:            var(--nm-p-noche);
    --nm-franja-linea:      var(--nm-p-linea-franja-osc);
    --nm-franja-linea-fuerte: var(--nm-p-linea-franja-fuerte-osc);
    --nm-franja-superficie: var(--nm-p-cerro);
  }
}

/* ── Impresión: papel cal y tinta, en cualquier modo ─────────
   Una lista de compras que no se puede imprimir es un hueco propio (ESPEC_UI
   §7). El papel es blanco aunque la pantalla esté de noche: se vuelven a
   declarar los semánticos del modo claro con sus primitivas, y va DESPUÉS de
   los dos bloques oscuros para ganarles por orden con la misma
   especificidad (`:root[data-theme="oscuro"]` y
   `:root:not([data-theme="claro"])` pesan lo mismo que sus gemelos de acá).

   Una diferencia deliberada con el claro de pantalla: la banda y las
   tarjetas van en cal y no en caliza. En pantalla la separación la hacen las
   franjas tonales; en papel la hacen los filetes, y un gris de fondo es tinta
   gastada que además la mayoría de los navegadores no imprime.

   `--nm-fondo` NO se redeclara acá, a propósito: es el color de página de
   cada MODO de pantalla, y `movil.js` pinta con él las barras del sistema
   (lo cuida `tests/test_capacitor.py`, que lee cada declaración de
   `--nm-fondo`). El papel no es un modo. El body impreso se pinta con la
   superficie —cal— desde el `@media print` de `estilo.css`, que es también
   donde vive qué se esconde y qué no se parte entre páginas. */
@media print {
  :root,
  :root[data-theme="oscuro"],
  :root:not([data-theme="claro"]) {
    color-scheme: light;
    --nm-superficie-1: var(--nm-p-cal);
    --nm-superficie-2: var(--nm-p-cal);
    --nm-superficie-3: var(--nm-p-cal);
    --nm-texto:        var(--nm-p-profundo);
    --nm-texto-2:      var(--nm-p-grafito);
    --nm-texto-3:      var(--nm-p-pizarra);
    --nm-borde-sutil:  var(--nm-p-linea-clr);
    --nm-borde:        var(--nm-p-linea-clr);
    --nm-borde-fuerte: var(--nm-p-linea-fuerte-clr);
    --nm-borde-tarjeta: var(--nm-p-linea-clr);
    --nm-primario:       var(--nm-p-anil);
    --nm-primario-tinta: var(--nm-p-hueso);
    --nm-primario-hover: var(--nm-p-anil-hover);
    --nm-acento:       var(--nm-p-ocre);
    --nm-acento-hover: var(--nm-p-ocre-hover);
    --nm-acento-suave: rgba(122, 89, 18, .10);
    --nm-nudo:         var(--nm-p-ambar);
    --nm-campo:        var(--nm-p-cal);
    --nm-error:        var(--nm-p-error-clr);
    --nm-foco:         var(--nm-p-ocre);
    --nm-sombra-1:     none;
    --nm-sombra-2:     none;
    --nm-velo-nav:     rgba(233, 235, 240, .90);
    --nm-velo:         rgba(13, 17, 32, .45);
    --nm-velo-foto:    rgba(13, 17, 32, .85);
    --nm-banda:        var(--nm-p-cal);
    --nm-banda-sup-1:  var(--nm-p-cal);
    --nm-banda-sup-2:  var(--nm-p-cal);
    --nm-banda-linea:  var(--nm-p-linea-clr);
  }
}

/* ── La forma: app o web, en un solo lugar ───────────────────
   ESPEC_UI §4. La app y la web de escritorio se ven diametralmente
   distintas y salen del mismo código, así que la pregunta «¿app o web?» se
   responde UNA vez, acá, como un juego de custom properties. Ninguna regla
   de componente vuelve a preguntarla: `hoja`, `barra`, `fab`, el colgante
   del hero y el alto de la cabecera leen estas variables.

   Por qué así y no con una media query por componente: una media query no
   se puede guardar en una variable, no se puede reutilizar y —lo que
   decide— no la puede ganar el cascarón de Capacitor, donde manda siempre
   la forma app sin mirar ancho ni puntero. Repetir
   `(max-width: 767px), (pointer: coarse) and (hover: none)` y su negación
   (`not all and (…)`) en veinte bloques es el desorden de diez anchos que
   el censo de breakpoints viene a cerrar.

   La condición va escrita DOS veces, igual que la paleta del modo oscuro y
   por el mismo motivo: CSS no sabe componer «media query O atributo». La
   @media es la base —funciona sin JavaScript y no parpadea— y el bloque
   `[data-forma="app"]` existe solo para que el cascarón mande. Lo escriben
   dos, y ninguno sobra: `empaquetar_web.py` (`forzar_forma_app`) lo pone en
   la etiqueta `<html>` de cada página del `www/`, que es lo que garantiza el
   CUÁNDO —está puesto cuando el parser lee la etiqueta, antes del primer
   pintado, donde ningún JavaScript llega—; y `web/js/forma.3c3e1697.js`
   (`fijarFormaApp`, que llama `movil.js` al armar el puente) garantiza la
   REGLA y cubre un `www/` viejo o un `CapacitorCustomPlatform`. En la web no
   lo escribe nadie: ahí manda la @media. Las dos listas declaran EXACTAMENTE
   las mismas propiedades: si una gana una variable y la otra no, la forma
   se rompe dentro del cascarón, que es justo donde nadie mira.

   El corte 767/768 es el mismo de `web/js/analitica.3c3e1697.js` (ANCHO_MOVIL), así
   que la forma y la telemetría quedan alineadas. El puntero va aparte
   porque un laptop de 1366 px a media pantalla mide 683 px y tiene mouse, y
   un teléfono en horizontal mide 915 px y tiene dedo. */
:root {
  /* Cabecera: 56 px, el cromo del rediseño 2026 (PANTALLAS §1 regla 2), y el
     mismo número en las dos formas — en app es título + «···» + avatar, y en
     web la misma fila lleva además el logo, las cinco pestañas y el campo que
     abre Buscar. Eran 109 y 119 con el buscador, el tema y las pestañas
     apiladas. Lo mide `tests/test_cabecera_ui.py` sobre la caja de verdad. */
  --nm-cabecera: 56px;
  /* Cromo inferior: en forma web no existe ninguna de las dos barras, y por
     eso valen 0 px — así el `scroll-padding-bottom` y el pie pueden sumarlas
     siempre, sin preguntar. */
  --nm-barra-tabs: 0px;
  /* La barra de compromiso solo reserva alto cuando existe —la enciende
     `html.con-barra`, que pone lista.js cuando la lista tiene productos— y
     solo en forma app: en web su chasis es `display: contents` y no tapa
     nada, así que ahí su alto máximo es 0. */
  --nm-barra: 0px;
  --nm-barra-max: 0px;
  /* `contents` y no `flex`: en forma web el chasis de la barra desaparece y
     su botón primario se queda exactamente donde está hoy, arriba de la
     columna derecha. Un solo primario en el documento, una sola verdad. */
  --nm-barra-display: contents;
  /* La hoja: en forma web es el menú anclado/centrado; en app sube de abajo.
     La capa siempre es el viewport entero —el velo lo pinta ella—, así que lo
     que cambia por forma es el PANEL: su ancho, su radio y contra qué borde
     se alinea. */
  --nm-hoja-ancho: min(92vw, 26rem);
  --nm-hoja-radio: var(--nm-radio-xl);
  --nm-hoja-alineado: center;
  --nm-hoja-asa: none;
  /* El colgante es la aparición grande del hero en forma web; en app no hay
     sitio para él (DESIGN.md, «Layout & Spacing»). */
  --nm-colgante-display: block;
}
@media (max-width: 767px), (pointer: coarse) and (hover: none) {
  :root:not([data-forma="web"]) {
    /* El tab bar flotante: 64 px de pastilla más los 18 que la despegan del
       borde. El `safe-area-inset-bottom` se suma aparte, una sola vez, donde
       se usa el token. */
    --nm-barra-tabs: 82px;
    --nm-barra-max: 74px;
    /* La barra de Mi semana (`.semana-barra`) es la única que apila resumen
       y botones en dos líneas en vez de una sola fila (reportado
       2026-09-24: apretada, se leía rota); necesita más alto que
       `--nm-barra-max`, que sigue midiendo la barra de una sola fila. */
    --nm-semana-barra-alto: 94px;
    --nm-barra-display: flex;
    --nm-hoja-ancho: 100%;
    --nm-hoja-radio: var(--nm-radio-xl) var(--nm-radio-xl) 0 0;
    --nm-hoja-alineado: end;
    --nm-hoja-asa: block;
    --nm-colgante-display: none;
    /* Display más chico: 52/36/26 son medidas de escritorio y en un teléfono
       el titular se come la primera pantalla. */
    --nm-d2: 30px;
    --nm-d3: 22px;
  }
}
:root[data-forma="app"] {
  --nm-barra-tabs: 82px;
  --nm-barra-max: 74px;
  --nm-semana-barra-alto: 94px;
  --nm-barra-display: flex;
  --nm-hoja-ancho: 100%;
  --nm-hoja-radio: var(--nm-radio-xl) var(--nm-radio-xl) 0 0;
  --nm-hoja-alineado: end;
  --nm-hoja-asa: block;
  --nm-colgante-display: none;
  --nm-d2: 30px;
  --nm-d3: 22px;
}
/* La barra de compromiso existe cuando la lista tiene productos, y solo
   entonces se le reserva sitio abajo. En forma web el chasis es
   `display: contents`, así que los 64 px no cuestan nada ahí. */
html.con-barra { --nm-barra: var(--nm-barra-max); }

/* ── Base ────────────────────────────────────────────────────
   El body SIEMPRE pinta su fondo con token; nunca transparente. */
.nm-base, body.nm-base {
  background: var(--nm-fondo);
  color: var(--nm-texto);
  font-family: var(--nm-cuerpo);
  transition: background-color var(--nm-mov-entrada) var(--nm-curva-suave),
              color var(--nm-mov-entrada) var(--nm-curva-suave);
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ── Clases tipográficas ─────────────────────────────────── */
.nm-d1 { font-family: var(--nm-cuerpo); font-weight: 700; font-size: var(--nm-d1); letter-spacing: var(--nm-d1-tracking); line-height: 1.1; }
.nm-d2 { font-family: var(--nm-cuerpo); font-weight: 700; font-size: var(--nm-d2); letter-spacing: var(--nm-d2-tracking); line-height: var(--nm-lh-display); }
.nm-d3 { font-family: var(--nm-cuerpo); font-weight: 700; font-size: var(--nm-d3); letter-spacing: var(--nm-d3-tracking); line-height: 1.2; }
.nm-d4 { font-family: var(--nm-cuerpo); font-weight: 700; font-size: var(--nm-d4); letter-spacing: var(--nm-d4-tracking); line-height: 1.2; }
/* El monto héroe: el dato ganador es de los dos únicos momentos serif de la
   app (el otro es el titular del hero). Bitter SOLO regular. */
.nm-precio {
  font-family: var(--nm-serif); font-weight: 400;
  font-size: var(--nm-precio); letter-spacing: var(--nm-precio-tracking);
  line-height: 1.1; font-variant-numeric: tabular-nums;
}
.nm-b1 { font-family: var(--nm-cuerpo); font-weight: 400; font-size: var(--nm-b1); line-height: var(--nm-lh-cuerpo); max-width: var(--nm-medida); }
.nm-b2 { font-family: var(--nm-cuerpo); font-weight: 400; font-size: var(--nm-b2); line-height: var(--nm-lh-cuerpo); }
.nm-b3 { font-family: var(--nm-cuerpo); font-weight: 400; font-size: var(--nm-b3); line-height: var(--nm-lh-ui); }
.nm-l1 { font-family: var(--nm-cuerpo); font-weight: 600; font-size: var(--nm-l1); letter-spacing: var(--nm-l1-tracking); text-transform: uppercase; }
.nm-num { font-variant-numeric: tabular-nums; }

/* ── Wordmark ────────────────────────────────────────────────
   «nada menos» en minúsculas, con «menos» en el oro de texto. */
.nm-logo {
  font-family: var(--nm-cuerpo); font-weight: 700;
  letter-spacing: -0.02em; line-height: 1;
}
.nm-logo .menos { color: var(--nm-acento); }

/* ── Componentes de referencia ───────────────────────────── */
/* Franja papel — la banda de trabajo. La frontera entre secciones mayores
   es un cambio de fondo a sangre completa (DESIGN, Layout & Spacing): la
   página en piedra, la banda un peldaño arriba en caliza con filete arriba
   y abajo, y dentro de la banda las tarjetas suben a cal vía el remapeo de
   tokens. El pintado lateral va en un ::before a sangre completa con el
   truco `50% + margen -50vw` (no `inset: 0 -100vmax`: en vertical, vmax
   toma el ALTO de pantalla, así que en un celular el pseudo-elemento salía
   más ancho que ninguna pantalla real, y algunos Chrome de Android
   permitían paso arrastrar igual aunque html lleve overflow-x: clip —
   desborde horizontal real, visto en dev el 2026-09-04). El z-index: 0
   hace de la banda su propio stacking context, con el ::before garantizado
   detrás del contenido. */
.nm-banda {
  --nm-superficie-1: var(--nm-banda-sup-1);
  --nm-superficie-2: var(--nm-banda-sup-2);
  position: relative;
  z-index: 0;
  background: var(--nm-banda);
  padding: var(--nm-esp-7) 0;
  transition: background-color var(--nm-mov-entrada) var(--nm-curva-suave);
}
.nm-banda::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: 50%; right: 50%;
  margin-left: -50vw; margin-right: -50vw;
  z-index: -1;
  background: inherit;
  border-top: 1px solid var(--nm-banda-linea);
  border-bottom: 1px solid var(--nm-banda-linea);
}

/* Franja índigo — la sección invertida que abre y cierra la página (hero
   y pie). En claro es índigo profundo con texto hueso; en oscuro no
   invierte, sube un nivel a noche. Remapea los semánticos para que todo
   lo que caiga adentro —wordmark, botones, enlaces, foco— se adapte solo:
   el oro dentro de la franja es siempre maíz, porque el fondo es oscuro
   en los dos modos. Máximo dos por página, y nunca en el medio. */
.nm-franja-indigo {
  --nm-fondo:          var(--nm-franja);
  --nm-superficie-1:   var(--nm-franja-superficie);
  --nm-superficie-2:   var(--nm-franja-superficie);
  --nm-texto:          var(--nm-franja-texto);
  --nm-texto-2:        var(--nm-franja-texto-2);
  --nm-texto-3:        var(--nm-franja-texto-3);
  --nm-borde-sutil:    var(--nm-franja-linea);
  --nm-borde:          var(--nm-franja-linea);
  --nm-borde-fuerte:   var(--nm-franja-linea-fuerte);
  --nm-borde-tarjeta:  var(--nm-franja-linea);
  --nm-acento:         var(--nm-franja-acento);
  --nm-acento-hover:   var(--nm-p-maiz-palido);
  --nm-acento-suave:   rgba(240, 196, 94, .12);
  --nm-nudo:           var(--nm-franja-nudo);
  --nm-foco:           var(--nm-franja-nudo);
  --nm-primario:       var(--nm-franja-boton);
  --nm-primario-tinta: var(--nm-franja-boton-tinta);
  --nm-primario-hover: var(--nm-p-helada-hover);
  --nm-campo:          var(--nm-franja-superficie);
  --nm-sombra-1:       none;
  position: relative;
  z-index: 0;
  background: var(--nm-franja);
  color: var(--nm-franja-texto);
  transition: background-color var(--nm-mov-entrada) var(--nm-curva-suave),
              color var(--nm-mov-entrada) var(--nm-curva-suave);
}
.nm-franja-indigo::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: 50%; right: 50%;
  margin-left: -50vw; margin-right: -50vw;
  z-index: -1;
  background: inherit;
}

/* El marcador de sección: uso 1 del motivo. Segmento de cuerda de 34px,
   trazo 3, y un nudo neutro de 12px en el remate; va sobre el H2 de cada
   sección y reemplaza al filete. Solo la sección focal de la página lleva
   el nudo en oro (`.nm-marcador--focal`). Nunca más de 2 en un viewport;
   con el logo suman 3. `.nm-cuerda` queda como alias del mismo dibujo. */
.nm-marcador, .nm-cuerda {
  display: flex; align-items: center;
  height: 12px; margin: 0 0 var(--nm-esp-4);
  border: 0; padding: 0; width: auto; background: none;
}
.nm-marcador i, .nm-cuerda i {
  display: block; width: 34px; height: 3px;
  border-radius: 2px; background: var(--nm-borde-fuerte);
}
.nm-marcador b, .nm-cuerda b {
  display: block; width: 12px; height: 12px; margin-left: -2px;
  border-radius: 50%; background: var(--nm-texto-3);
}
.nm-marcador--focal b { background: var(--nm-nudo); }

/* El colgante de portada: uso 2 del motivo. Tres cuerdas caen del borde
   superior del hero a distinto largo —el gesto del isotipo— con un solo
   nudo de maíz a media caída de la MÁS CORTA (en Nada Menos las cuerdas
   descienden porque cuentan una reducción: la más corta es el precio más
   bajo, y ahí gana tu plata; al revés que en el símbolo de Curaca) y el
   resto en neutro. Cuenta
   como UNA aparición grande; sangra fuera del lienzo y se oculta en móvil.
   El SVG lo pone el HTML (index.html); acá solo su sitio y su color. */
/* El colgante es cosa de la forma web, así que se apaga con la variable de
   forma y no con un ancho propio: el 720 de antes no tenía par en ningún
   otro archivo, y con esto tokens.css queda sin ninguna media query de
   ancho fuera del interruptor de forma. */
.nm-colgante {
  display: var(--nm-colgante-display);
  position: absolute; top: 0; right: clamp(24px, 8vw, 120px);
  width: 120px; height: 100%; max-height: 240px;
  color: var(--nm-borde-fuerte);
  pointer-events: none;
}

/* `.nm-tarjeta`, `.nm-tarjeta-ganadora` (nombre sin BEM, nunca usado en el
   marcado — la ganadora real es `.nm-tarjeta--ganadora`), `.nm-boton` y
   `.nm-boton:hover` vivían acá duplicados de `componentes.css`, que carga
   DESPUÉS (index.html/portada.html: tokens → componentes → estilo) y ya
   redefine fondo/borde/radio/tipografía con las mismas reglas de cascada.
   Lo único que no era puro duplicado eran las `transition` de color, que
   `componentes.css` no declaraba — se migraron ahí (ver `.nm-tarjeta` y
   `.nm-boton` en ese archivo). El `.nm-boton:hover` genérico se borró
   entero: no hay ningún `.nm-boton` sin modificador en el marcado (grep en
   `web/` y `web/galeria/`), y aun si lo hubiera, cualquier variante
   (`--primario`, `--secundario`, `--terciario`, `--circular`, `--puesto`)
   tiene mayor especificidad en su propio `:hover` de `componentes.css` y
   ganaría igual — este quedaba siempre sin efecto, y sin la consulta
   `(hover: hover) and (pointer: fine)` habría sido el bug real si algo lo
   hubiera alcanzado alguna vez. */
