/**
 * ============================================================
 * NAHUEN GOURMET MARKET — Framework Visual (Fase 7)
 * ============================================================
 * Concepto director: "La Sobremesa" — ver 05-diseno/direccion-arte.md
 * Fuente de verdad estética: 05-diseno/direccion-arte.md (validado)
 * Fuente de verdad de identidad: 05-diseno/contexto-identidad-visual.md
 *
 * Este archivo es el sistema visual completo y reutilizable del proyecto.
 * NO PHP, NO WordPress, NO JS dinámico — CSS puro, listo para producción
 * (las clases se aplican como clases globales en Bricks; este archivo se
 * encola desde el plugin nahuen-functions).
 *
 * Metodología: custom properties + BEM + fluidez obligatoria (clamp()).
 * Excepción deliberada de fluidez: border-radius (fijo en 0, sección 25 de
 * la dirección de arte — no es "un valor que escala mal", es una restricción
 * de marca no negociable) y las dos categorías de duración de motion
 * (350ms interacción expresiva / 150-250ms feedback utilitario — fijas por
 * decisión explícita de la dirección de arte, sección 22, no por viewport).
 *
 * ÍNDICE
 *  1. Fuentes (@font-face)
 *  2. Variables — Color
 *  3. Variables — Tipografía
 *  4. Variables — Espaciado
 *  5. Variables — Radius / Sombra / Línea
 *  6. Variables — Motion (timing)
 *  7. Variables — Iconografía / Overlay / Z-index
 *  8. Reset
 *  9. Tipografía base (h1-h6, body, links)
 * 10. Layout — contenedor, grids fluidos, sidebar layouts, stack
 * 11. Bloques cromáticos (secciones)
 * 12. Navegación
 * 13. Hero editorial / monumental
 * 14. Botones y CTA
 * 15. Cards fantasma / grids de catálogo
 * 16. Identificadores de línea de negocio
 * 17. Iconografía — overlay compositivo + funcional
 * 18. Cutouts / imágenes
 * 19. Formularios
 * 20. Badges / Alerts / Skeleton / Empty state / FAQ
 * 21. Footer
 * 22. Utilidades
 * 23. Accesibilidad — prefers-reduced-motion
 * 24. Motion — sección reservada (ver motion-system.css)
 * ============================================================
 */

/* ============================================================
   1. FUENTES (@font-face)
   Rutas relativas a ../Fuentes/ desde 06-framework/framework.css.
   Gate legal (Fase 9.5, no bloqueante para diseño/maquetación):
   Beaufort Pro es DEMO de Fontspring (sin licencia webfont) y ATHENA está
   marcada "Personal Use Only" — habilitadas para diseñar/maquetar,
   NO para publicar en producción sin resolver licencia.
   Preload recomendado (documentado en framework-ui.md): DM Serif Display
   + Beaufort Pro Bold/Medium (fuentes del hero, above-the-fold).
   ============================================================ */

@font-face {
  font-family: "DM Serif Display";
  src: url("../Fuentes/DMSerifDisplay-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Retro Signature";
  src: url("../Fuentes/RETROSIGNATURE.OTF") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauLigh-iF66728d55ae102.otf")
    format("opentype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauLigI-iF66728d55a6eb9.otf")
    format("opentype");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauReg_-iF66728d559407c.otf")
    format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauRegI-iF66728d558d06e.otf")
    format("opentype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauMed_-iF66728d559ef57.otf")
    format("opentype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauMedI-iF66728d559909c.otf")
    format("opentype");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauBold-iF66728d55c4a27.otf")
    format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauBolI-iF66728d55bf06a.otf")
    format("opentype");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauHeav-iF66728d55b4182.otf")
    format("opentype");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Beaufort Pro";
  src: url("../Fuentes/Beaufort Pro (DEMO Fontspring - pendiente licencia web)/Fontspring-DEMO-BeauHeaI-iF66728d55ba160.otf")
    format("opentype");
  font-weight: 800;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "ATHENA";
  src: url("../Fuentes/Athena-Regular (PERSONAL USE ONLY).ttf")
    format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  /* Nota: el brand guideline declara ATHENA Regular + Semibold. El peso Semibold
     no tiene archivo entregado todavía — usar ATHENA Regular en todos los
     destacados hasta que se reciba (direccion-arte.md, sección 16). */
}

@font-face {
  font-family: "Poppins";
  src: url("../Fuentes/Poppins-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  /* Poppins Medium (500) y SemiBold (600) NO están self-hosted todavía —
     no existen como archivo en Fuentes/. Pendiente de descarga desde Google
     Fonts para self-hosting antes de producción (ver framework-ui.md).
     La demo de este framework los carga temporalmente vía Google Fonts CDN. */
}

/* ============================================================
   2 · 3 · 4 · 5 · 6 · 7 — VARIABLES DEL SISTEMA
   ============================================================ */
:root {
  /* ---- 2. Color — paleta de marca (fuente: direccion-arte.md, sección 15) ---- */
  --nahuen-cream: #fdfbf7; /* Light Cream — fondo dominante */
  --nahuen-rosa: #f2e9ea; /* Rosa Viejo Lavado — transición */
  --nahuen-sage: #d9e5f0; /* Soft Sage Blue — EXCLUSIVO Market/salado */
  --nahuen-bordo: #642128; /* Bordó Nahuen — fondo alto impacto + trazo */
  --nahuen-bordo-detalle: #774c51; /* Bordó Detalle — acento, NUNCA fondo dominante */
  --nahuen-crema-marca: #f8f2e4; /* Crema de marca — solo dentro de imágenes/papelería */
  --nahuen-ink: #222222; /* Neutral Black — tinta de cuerpo de texto */

  /* Mapeo a nomenclatura genérica del sistema (compatibilidad con el framework
     estándar del track — usar los tokens --nahuen-* semánticos en componentes
     nuevos, estos alias existen para utilidades transversales del sistema). */
  --color-primary: var(--nahuen-bordo);
  --color-secondary: var(--nahuen-bordo-detalle);
  --accent-to-go: #968c83; /* Pantone 7533 C "To Go" — uso quirúrgico como acento
     temático puntual de esa línea de negocio (direccion-arte.md, sección 15).
     NUNCA neutral genérico de UI (bordes/disabled usan color-mix de --nahuen-ink,
     ver más abajo). No consumido por ningún componente todavía. */
  /* Paleta funcional (attention/success/warning/error) — EXTENSIÓN PENDIENTE DE
     VALIDACIÓN: ninguno de estos 4 hex existe en direccion-arte.md (sistema de
     color cerrado y "decisional"). Necesarios funcionalmente (estados de
     formulario/alert) pero deben pasar por gate con diseñador/cliente antes de
     Fase 8 (hallazgo del panel de crítica, severidad media — ver framework-ui.md
     "Extensiones pendientes de validación"). Color de atención NUNCA es color de
     marca. Terracota, hue distinto (naranja vs. rojo-violeta del bordó).
     Contraste verificado ≈5.7:1 sobre Light Cream (AA texto normal). Uso
     restringido a fondos claros (Cream/Rosa/Sage) — sobre Bordó usar Light Cream
     + borde de color en vez de texto coloreado (ver framework-ui.md). */
  --color-attention: #a34a1a;
  --color-success: #4b6b3a; /* verde oliva muted — contraste ≈5.9:1 sobre Cream */
  --color-warning: #7a5710; /* ámbar oscuro — contraste ≈4.9:1 sobre su fondo mix (AA), corregido tras QA de contraste (era #8C6614, 4.31:1, insuficiente) */
  --color-error: #b23a2e; /* rojo-naranja, distinto hue del bordó — contraste ≈5.7:1 sobre Cream */
  --color-text: var(--nahuen-ink);
  /* Derivado documentado de la tinta de cuerpo (NUNCA un gris genérico inventado,
     direccion-arte.md sección 15: "nunca gris genérico" / "nunca texto gris
     lavado sobre fondo de color"). Excepción validada de uso: SOLO labels
     flotantes en reposo y filtros inactivos (chrome de UI, no texto de cuerpo).
     Texto de cuerpo real (descripciones de card, respuestas de FAQ, empty state)
     usa --color-text a secas — ver framework-ui.md. */
  --color-text-muted: color-mix(
    in srgb,
    var(--nahuen-ink) 75%,
    var(--nahuen-cream)
  );
  --color-text-inverse: var(--nahuen-cream);
  --color-background: var(--nahuen-cream);
  --color-surface: var(--nahuen-rosa);
  --color-surface-market: var(--nahuen-sage);

  /* ---- 3. Tipografía — familias (fuente: direccion-arte.md, sección 16) ---- */
  --font-hero: "DM Serif Display", Georgia, "Times New Roman", serif;
  --font-display-season: "Retro Signature", cursive;
  --font-heading: "Beaufort Pro", Georgia, "Times New Roman", serif;
  --font-accent: "ATHENA", Georgia, serif;
  --font-body:
    "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Escala tipográfica fluida — EXACTA a la tabla de direccion-arte.md sección 16.
     No se inventan nuevas fórmulas de clamp(); rango de referencia 360px–1440px. */
  --text-hero: clamp(
    3.5rem,
    1.875rem + 5vw,
    7.5rem
  ); /* Hero monumental — DM Serif Display. Techo reducido de 9rem a 7.5rem
     (decisión del usuario, feedback Agentation 2026-07-05): fórmula del
     término medio y techo escalados proporcionalmente (×5/6) manteniendo el
     piso mobile de 3.5rem sin cambios — ver framework-ui.md sección 3. */
  --text-season: clamp(
    2rem,
    1.5rem + 2.5vw,
    3.5rem
  ); /* Display temporada — Retro Signature */
  --text-h1: clamp(
    2.5rem,
    2rem + 2.5vw,
    4rem
  ); /* H1 institucional — Beaufort Bold */
  --text-h2: clamp(
    1.875rem,
    1.5rem + 1.8vw,
    3rem
  ); /* H2 sección — Beaufort Medium/Bold */
  --text-h3: clamp(
    1.375rem,
    1.2rem + 0.8vw,
    1.875rem
  ); /* H3 subtítulo/card title — Beaufort Medium */
  --text-quote: clamp(
    1.25rem,
    1.1rem + 0.7vw,
    1.75rem
  ); /* Destacado/cita — ATHENA */
  --text-body-lg: clamp(
    1.125rem,
    1.05rem + 0.35vw,
    1.25rem
  ); /* Body large (Beaufort narrativo o Poppins) */
  --text-body: clamp(
    1rem,
    0.95rem + 0.2vw,
    1.125rem
  ); /* Body base — Poppins Regular */
  --text-body-sm: clamp(
    0.875rem,
    0.83rem + 0.2vw,
    0.9375rem
  ); /* Body pequeño (~14-15px) — NUEVO, ronda de referencias 2026-07-05.
     Propuesta de analisis-visual.md sección 3/14: texto repetido de alta
     frecuencia (card-ghost__text, descripciones de módulo en Accesos)
     nunca comparte tamaño con la bajada de hero ni la intro de bloque.
     --text-body-lg queda EXCLUSIVO del lead del hero; --text-body queda
     para párrafos narrativos de 1-3 líneas (intro de bloque, historia).
     PROPUESTA APLICADA — pendiente ratificar en direccion-arte.md (ver
     framework-ui.md, "Registro de refinamiento v4"). Contraste verificado
     a este tamaño: Neutral Black sobre Cream/Rosa/Sage sigue ≥AA (hereda
     el mismo --color-text, ninguna reducción de contraste, solo de escala). */
  --text-caption: clamp(
    0.75rem,
    0.7rem + 0.15vw,
    0.875rem
  ); /* Caption/label/badge — Poppins Medium */

  /* Identificadores de línea de negocio (direccion-arte.md, sección 16) */
  --text-kicker: var(--text-caption); /* mismo tier que caption */
  --text-line-header: clamp(
    1rem,
    0.9rem + 0.5vw,
    1.375rem
  ); /* techo = piso de H3, nunca lo alcanza */

  /* Alias de compatibilidad con nomenclatura genérica del sistema (no usar en
     componentes nuevos — usar los tokens --text-* semánticos de arriba). */
  --font-size-xs: var(--text-caption);
  --font-size-sm: var(--text-body);
  --font-size-base: var(--text-body);
  --font-size-lg: var(--text-body-lg);
  --font-size-xl: var(--text-h3);
  --font-size-2xl: var(--text-h2);
  --font-size-3xl: var(--text-h1);
  --font-size-4xl: var(--text-hero);
  --font-h1: var(--text-h1);
  --font-h2: var(--text-h2);
  --font-h3: var(--text-h3);
  --font-h4: var(--text-body-lg);
  --font-h5: var(--text-body);
  --font-h6: var(--text-caption);

  /* ---- 4. Espaciado — dos tiers de sección (direccion-arte.md, sección 25) ---- */
  --space-section-narrative: clamp(
    4rem,
    3rem + 6vw,
    9rem
  ); /* hero, bloques Borgoña, Our Story */
  --space-section-utility: clamp(
    3rem,
    2rem + 5vw,
    6rem
  ); /* NAP, formularios, catálogo */
  --space-section-x: clamp(
    1.25rem,
    1rem + 3vw,
    4rem
  ); /* margen lateral de contenido */
  --space-grid-gap: clamp(
    1rem,
    0.8rem + 1vw,
    2rem
  ); /* gap entre cards fantasma */
  --space-block-gap: 0; /* bloques cromáticos SIN gap — el corte de color separa */
  --measure-reading: clamp(
    20rem,
    18rem + 30vw,
    42rem
  ); /* ancho máx. de columna de lectura (blog/legal, contenedor dedicado) */
  --measure-body: 62ch; /* NUEVO — medida global de párrafo (~58-62ch),
     analisis-visual.md sección 6/14: "cualquier body copy centrado a ancho
     completo de viewport sin límite de medida" es un error de ejecución.
     Aplicado como default de <p> (sección 9) — un contenedor más angosto
     (grid, card) ya lo acota antes de llegar a este techo. */
  --measure-card: 32ch; /* medida más corta para texto repetido de card/módulo
     (card-ghost__text, .module-row p) — nunca la misma medida que un
     párrafo narrativo suelto. */

  /* Escala micro genérica (botones, badges, forms, gaps pequeños — sin
     definición explícita en direccion-arte.md a este nivel de detalle;
     extrapolada por el Maquetador dentro del mismo rango de referencia
     360px–1440px, coherente con la escala de espaciado de sección). */
  --space-xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem);
  --space-sm: clamp(0.5rem, 0.4rem + 0.5vw, 1rem);
  --space-md: clamp(1rem, 0.8rem + 1vw, 1.5rem);
  --space-lg: clamp(1.5rem, 1.2rem + 1.5vw, 2rem);
  --space-xl: clamp(2rem, 1.5rem + 2.5vw, 3rem);
  --space-2xl: clamp(3rem, 2rem + 4vw, 4rem);
  --space-3xl: clamp(4rem, 3rem + 5vw, 6rem);
  --space-4xl: clamp(6rem, 4rem + 8vw, 10rem);

  /* ---- 5. Radius / Sombra / Línea ---- */
  /* Border-radius: 0 en TODO el sitio, sin excepción (anti-regla 2). No hay
     escala de radius porque no hay rango aceptable de redondeo — es una
     restricción binaria de marca, no un valor que "escala mal". */
  --radius: 0;

  /* Grosor de línea divisoria — 1px por defecto, 0.5px en pantallas retina
     (direccion-arte.md sección 25; ver media query más abajo). */
  --line-thickness: 1px;

  /* Sombra — casi nula por diseño (intensificador "Sombras: 1/5", sección 6).
     --shadow-cutout es la ÚNICA sombra funcional del sistema: separa una
     imagen flotante de un fondo de luminosidad similar. NUNCA glow/blur
     decorativo, NUNCA en botones/cards/inputs/badges (anti-regla 9). */
  --shadow-none: none;
  --shadow-cutout: drop-shadow(
    0 clamp(2px, 1px + 0.3vw, 6px) clamp(4px, 2px + 0.6vw, 10px)
      rgb(34 34 34 / 0.18)
  );
  /* No existe escala --shadow-sm/md/lg/xl en este proyecto (removida en
     refinamiento post-panel): direccion-arte.md fija "Sombras: 1/5" con
     --shadow-cutout como ÚNICA sombra legítima del sistema y prohíbe la sombra
     difusa decorativa (anti-regla 9). Mantener un catálogo de sombras genéricas
     invitaba al mal uso en Fase 8/9. Si un caso futuro lo necesitara realmente,
     pasa por Evolución sistémica documentada en framework-ui.md. */

  /* ---- 6. Motion — timing (direccion-arte.md, sección 22) ----
     Fijas por decisión explícita, NO fluidas: son estándares de calidad de
     interacción (350ms mínimo expresivo, 150-250ms feedback), no valores que
     deban escalar con el viewport. La duración de reveals de scroll NO es un
     token CSS — se gobierna en JS (gsap.utils.mapRange), ver motion.js. */
  --duration-interactive: 350ms; /* mouse/hover expresivo: magnetismo, CTA, fill de botón */
  --duration-feedback: 200ms; /* feedback utilitario: link nav, inputs (rango 150-250ms) */
  --ease-interactive: cubic-bezier(0.645, 0.045, 0.355, 1); /* ease-in-out */
  --ease-feedback: ease-out;
  --ease-reveal: cubic-bezier(
    0.16,
    1,
    0.3,
    1
  ); /* ease-out-expo, referencia para JS */
  --transition-interactive: var(--duration-interactive) var(--ease-interactive);
  --transition-feedback: var(--duration-feedback) var(--ease-feedback);

  /* ---- 7. Iconografía / Overlay / Z-index ---- */
  --icon-s: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  --icon-m: clamp(1.25rem, 1rem + 1.25vw, 1.75rem);
  --icon-l: clamp(1.75rem, 1.5rem + 1.25vw, 2.25rem);
  --icon-xl: clamp(2rem, 1.5rem + 2.5vw, 3rem);
  --icon-functional: clamp(
    3rem,
    2.25rem + 3vw,
    5rem
  ); /* ícono protagonista, Accesos Rápidos */

  /* Overlay compositivo — escalas y opacidad por tipo de sección, fuente única
     de verdad: direccion-arte.md sección 20. Cada instancia puede sobreescribir
     --icon-overlay-opacity puntualmente dentro del rango documentado (4-15%). */
  --overlay-scale-hero: clamp(14rem, 9rem + 16vw, 36rem);
  --overlay-scale-impact: clamp(18rem, 10rem + 18vw, 40rem);
  --overlay-scale-pattern: clamp(6rem, 4rem + 6vw, 14rem);
  --overlay-scale-transition: clamp(10rem, 6rem + 10vw, 24rem);
  --overlay-scale-watermark: clamp(8rem, 5rem + 8vw, 18rem);

  /* Esquema de capas — decálogo del manual V2 (direccion-arte.md, sección 20).
     Obligatorio y sin excepción salvo el entrelazado del hero (fragmento a
     fragmento, resuelto localmente en .hero-monumental). */
  --z-texture: 1; /* macro-fondos, overlays de iconografía */
  --z-text: 2; /* texto base */
  --z-cutout: 3; /* imágenes cut-out flotantes */
  --z-nav: 10;
  --z-overlay-ui: 20; /* menú móvil, modales */
}

/* Línea divisoria 0.5px en pantallas de alta densidad (direccion-arte.md, sección 25) */
@media (min-resolution: 2dppx) {
  :root {
    --line-thickness: 0.5px;
  }
}

/* ============================================================
   8. RESET
   ============================================================ */
*,
*::before,
*::after {
  box-sizing: border-box;
}
* {
  margin: 0;
}
html {
  -webkit-text-size-adjust: 100%;
  color-scheme: light;
}
body {
  min-height: 100dvh;
  background: var(--color-background);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img,
picture,
svg {
  display: block;
  max-width: 100%;
}
input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}
button {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
}
a {
  color: inherit;
  text-decoration: none;
}
ul,
ol {
  list-style: none;
  padding: 0;
}
table {
  border-collapse: collapse;
  width: 100%;
}
/* Border-radius 0 explícito en los elementos donde el navegador aplica
   redondeo nativo por defecto (inputs/selects en algunos navegadores). */
input,
textarea,
select,
button {
  border-radius: var(--radius);
}
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* ============================================================
   9. TIPOGRAFÍA BASE (h1-h6, body, links)
   ============================================================ */
h1,
.h1 {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-h1);
  line-height: 1.1;
  letter-spacing: -0.005em;
}
h2,
.h2 {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-h2);
  line-height: 1.15;
  letter-spacing: -0.005em;
}
/* Modificador de heading — evita que un título largo quede en una sola
   línea corrida (hallazgo Agentation 2026-07-05, título de Locations).
   Componente reutilizable en cualquier h1-h6 con título largo, no solo h2 —
   se aplica vía clase del sistema, nunca inline. */
.h1--balance,
.h2--balance,
.h3--balance {
  max-inline-size: 20ch;
  text-wrap: balance;
}
h3,
.h3 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--text-h3);
  line-height: 1.2;
}
/* h4-h6: sin definición explícita en direccion-arte.md a este nivel —
   decisión del Maquetador, extrapolación conservadora dentro de la escala
   existente (nunca inventa tamaños nuevos, reutiliza los tokens ya
   definidos). Pesos corregidos a caras realmente self-hosted (300/400/500/
   700/800 en Beaufort Pro, solo 400 en Poppins self-hosted): 600 no existe
   como archivo — el navegador lo resolvía a un faux-weight. Documentado en
   framework-ui.md. */
h4,
.h4 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--text-body-lg);
  line-height: 1.3;
}
h5,
.h5 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--text-body);
  line-height: 1.4;
}
h6,
.h6 {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.4;
}
p {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.7;
  /* Medida global de párrafo (Fix D, ronda de referencias 2026-07-05) — un
     contenedor más angosto (grid/card) ya acota antes de llegar a este
     techo; el override explícito de un contenedor dedicado (--measure-reading
     en .container--narrow, style inline puntual) sigue ganando por cascada/
     especificidad donde ya existía. */
  max-inline-size: var(--measure-body);
}
a:not([class]) {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Registros tipográficos especiales — componentes, no headings genéricos.
   Se aplican sobre el elemento semántico correspondiente (normalmente <h1>
   dentro de .hero-monumental, <blockquote> para citas, etc.) */
.hero-monumental__title {
  font-family: var(--font-hero);
  font-weight: 400;
  font-size: var(--text-hero);
  line-height: 0.97;
  letter-spacing: -0.01em;
}
.season-badge {
  font-family: var(--font-display-season);
  font-weight: 400;
  font-size: var(--text-season);
  line-height: 1;
}
.quote-monumental {
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: var(--text-quote);
  line-height: 1.3;
}
/* Cifra/dato destacado — ATHENA a escala menor que la cita (ej. "25 años" en
   el bloque "Lo que nos une", direccion-arte.md sección 27: la cifra va en
   ATHENA, no en caption Poppins — añadido en refinamiento post-panel, la
   maqueta lo necesitaba y no existía componente para eso). */
.stat-highlight {
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: var(--text-h3);
  line-height: 1.2;
}
.text-body-lg {
  font-family: var(--font-body);
  font-size: var(--text-body-lg);
  line-height: 1.65;
}
/* Body pequeño — texto repetido de alta frecuencia (NUEVO, ronda de
   referencias 2026-07-05). Ver --text-body-sm arriba. Reutilizado por
   .card-ghost__text y .module-row p (sección 15/nueva), documentado acá
   como utilidad para cualquier otro texto repetido puntual. */
.text-body-sm {
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  line-height: 1.6;
  max-inline-size: var(--measure-card);
}
/* Registro "corrido" narrativo — Beaufort Pro Regular, bloques de historia
   (Our Story, Lo que nos une, intro de Seasonal). Ver direccion-arte.md 16. */
.text-body-lg--editorial {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: var(--text-body-lg);
  line-height: 1.6;
}
.text-caption,
.caption {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.4;
}
.text-muted {
  color: var(--color-text-muted);
}
.text-inverse {
  color: var(--color-text-inverse);
}

/* ============================================================
   10. LAYOUT — contenedor, grids fluidos, sidebar, stack
   ============================================================ */
.container {
  width: 100%;
  max-width: 90rem;
  margin-inline: auto;
  padding-inline: var(--space-section-x);
}
.container--narrow {
  max-width: var(--measure-reading);
}
.stack > * + * {
  margin-top: var(--space-md);
}
.stack--lg > * + * {
  margin-top: var(--space-xl);
}
.stack--sm > * + * {
  margin-top: var(--space-sm);
}

/* Grids fluidos obligatorios del sistema */
.grid-s {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr));
  gap: var(--space-sm);
}
.grid-m {
  display: grid;
  /* min(X, 100%) evita overflow horizontal cuando el viewport es menor que el
     mínimo nominal de la columna (hallazgo del panel: 17.5rem/25rem producían
     overflow bajo ~320-432px, recortado silenciosamente por overflow-x:clip
     de .section). */
  grid-template-columns: repeat(auto-fit, minmax(min(17.5rem, 100%), 1fr));
  gap: var(--space-grid-gap);
}
.grid-l {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(25rem, 100%), 1fr));
  gap: var(--space-grid-gap);
}
.grid-2-col {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-xl);
}
@media (max-width: 48em) {
  .grid-2-col {
    grid-template-columns: 1fr;
  }
}

/* Grid asimétrico — módulo líder a doble ancho + desalineación vertical
   escalonada (direccion-arte.md, "Accesos rápidos", sección 27). No es
   declarativo: los offsets concretos están fijados aquí. */
.grid-asymmetric {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-grid-gap);
}
/* Fix C (ronda de referencias 2026-07-05): cada módulo se alinea por su
   propia altura de contenido (nunca por stretch de CSS Grid) — combinado
   con los presupuestos de línea de .module-row, esto es lo que hace que
   los 4 módulos terminen parejos SIN depender de que todos midan lo mismo
   por casualidad. El offset vertical escalonado (nth-child de abajo) es la
   asimetría DELIBERADA del sistema (direccion-arte.md sección 27) y sigue
   intacta; lo que se elimina es la desalineación ACCIDENTAL por texto libre. */
.grid-asymmetric__item {
  align-self: start;
}
.grid-asymmetric__item--lead {
  grid-column: span 2;
}
/* Offsets ajustados para que el techo (1440px) quede dentro de la banda
   2-3rem que fija direccion-arte.md sección 27 para la desalineación
   vertical del bloque Accesos Rápidos (antes dos de los tres salían de
   rango: 3.5rem y 1rem). */
.grid-asymmetric__item:nth-child(2) {
  margin-top: clamp(1.5rem, 1rem + 2vw, 3rem);
}
.grid-asymmetric__item:nth-child(3) {
  margin-top: clamp(1.25rem, 0.9rem + 1vw, 2rem);
}
.grid-asymmetric__item:nth-child(4) {
  margin-top: clamp(1.75rem, 1.3rem + 1.5vw, 2.75rem);
}
@media (max-width: 48em) {
  .grid-asymmetric {
    grid-template-columns: 1fr;
  }
  .grid-asymmetric__item,
  .grid-asymmetric__item--lead {
    grid-column: span 1;
    margin-top: 0;
  }
}

/* Pattern nuevo — módulo icono+título+texto+CTA (Fix C, ronda de
   referencias 2026-07-05). Nace en Accesos Rápidos (.grid-asymmetric__item)
   pero es un Pattern reutilizable — direccion-arte.md sección 27 pide el
   mismo patrón (ícono funcional + título + texto) para "Valores" de Our
   Story con menor densidad. Se aplica como clase adicional sobre el
   contenedor (`class="grid-asymmetric__item module-row"`), nunca
   reemplazando la clase de grid — separa posicionamiento (grid) de
   composición interna (module-row). Usa selectores de descendiente sobre
   componentes ya BEM (.icon-functional, .h3, <p>, .btn) en vez de renombrar
   cada elemento — mismo criterio ya usado en `.nav__mobile .nav__link`. */
.module-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.module-row .icon-functional {
  margin-block-end: var(--space-md);
}
.module-row .h3 {
  margin-block-end: var(--space-xs);
  /* Reserva 2 líneas — mismo criterio que .card-ghost__title, así el título
     más corto de la fila no queda más alto que el más largo. */
  min-height: 2.4em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.module-row p {
  margin-block-end: var(--space-sm);
  /* Tier chico (--text-body-sm, Fix B) + presupuesto de 3 líneas (Fix C) —
     mismo criterio que .card-ghost__text, sin duplicar la clase en el HTML
     de cada módulo. */
  font-size: var(--text-body-sm);
  line-height: 1.6;
  max-inline-size: var(--measure-card);
  min-height: 4.8em;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.module-row .btn {
  margin-block-start: var(--space-sm);
}

/* Grid de catálogo — módulo insignia a doble ancho con desalineación vertical
   (Archive:Cake, Archive:ProductoMercado, Archive:Merch — direccion-arte.md 27) */
.grid-catalog {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-grid-gap);
}
/* Fix C: mismo criterio que .grid-asymmetric — altura por contenido, nunca
   por stretch (necesario en filas mixtas, ej. Locations: 1 card con foto +
   2 entradas de texto sin foto todavía — sin esto, CSS Grid estira las
   entradas de texto a la altura de la card con foto, dejando un hueco
   vacío enorme debajo del texto). */
.grid-catalog__item {
  align-self: start;
}
.grid-catalog__item--insignia {
  grid-column: span 2;
  margin-top: clamp(1.5rem, 1rem + 2vw, 2rem);
}
@media (max-width: 48em) {
  .grid-catalog {
    grid-template-columns: 1fr;
  }
  .grid-catalog__item--insignia {
    grid-column: span 1;
    margin-top: 0;
  }
}

/* Layouts con sidebar — capacidad genérica del sistema (disponible para
   templates futuros como Blog con filtros; ningún wireframe actual de
   Nahuen usa sidebar, documentado en framework-ui.md). */
.layout-sidebar-right {
  display: grid;
  grid-template-columns: 1fr clamp(200px, 25vw, 320px);
  gap: var(--space-xl);
}
.layout-sidebar-left {
  display: grid;
  grid-template-columns: clamp(200px, 20vw, 280px) 1fr;
  gap: var(--space-xl);
}
.layout-full {
  display: grid;
  grid-template-columns: 1fr;
}
.sidebar-sticky {
  position: sticky;
  top: var(--space-lg);
  align-self: start;
}
.sidebar-collapsible[data-collapsed="true"] {
  display: none;
}
@media (max-width: 48em) {
  .layout-sidebar-right,
  .layout-sidebar-left {
    grid-template-columns: 1fr;
  }
  .sidebar-sticky {
    position: relative;
    top: 0;
  }
}

/* ============================================================
   11. BLOQUES CROMÁTICOS (secciones)
   Ritmo Cream → Rosa → Borgoña, sin gap — el corte de color ES el separador.
   Nunca dos .section del mismo tono consecutivas (regla de composición, no
   forzable por CSS — ver checklist QA de Fase 8).
   ============================================================ */
.section {
  position: relative;
  overflow-x: clip; /* contiene el bleed de cutouts sin generar scroll horizontal */
  padding-block: var(--space-section-utility);
  /* La nav es fixed — sin esto, navegar a un ancla (#accesos, etc.) deja el
     título tapado detrás de la barra (hallazgo QA). */
  scroll-margin-top: var(--space-3xl);
}
.section--narrative {
  padding-block: var(--space-section-narrative);
}
.section--full {
  min-height: 100svh;
  display: flex;
  align-items: center;
}
/* Defensa estructural: TODA sección debe llevar la clase base .section (aporta
   position:relative + overflow-x:clip). Esta regla es un respaldo — si un
   modificador se usa solo (sin .section, error de maquetación en Bricks), al
   menos no rompe el posicionamiento absoluto de sus hijos (overlays, cutouts).
   No sustituye a .section: NO trae overflow-x:clip ni el padding-block base. */
.section--cream,
.section--rosa,
.section--sage,
.section--bordo,
.section--bordo-narrow {
  position: relative;
}
.section--cream {
  background: var(--nahuen-cream);
  color: var(--color-text);
}
.section--rosa {
  background: var(--nahuen-rosa);
  color: var(--color-text);
}
.section--sage {
  background: var(--nahuen-sage);
  color: var(--color-text);
}
.section--bordo {
  background: var(--nahuen-bordo);
  color: var(--color-text-inverse);
}
/* Franja Borgoña angosta — CTA de cierre, no bloque narrativo completo */
.section--bordo-narrow {
  background: var(--nahuen-bordo);
  color: var(--color-text-inverse);
  padding-block: var(--space-lg);
}

/* ============================================================
   12. NAVEGACIÓN
   Transparente sobre el hero, se solidifica al hacer scroll (.nav--solid,
   toggle vía motion.js). Hamburguesa solo-CSS + JS mínimo obligatorio.
   ============================================================ */
.nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--space-sm);
  padding-inline: var(--space-section-x);
  background: transparent;
  color: var(--color-text);
  /* Solo background transiciona — el padding nunca cambia entre .nav y
     .nav--solid (era código muerto, removido en refinamiento post-panel). */
  transition: background var(--transition-feedback);
}
.nav--solid {
  background: var(--nahuen-cream);
  box-shadow: 0 var(--line-thickness) 0 rgb(34 34 34 / 0.08);
}
.nav--on-dark {
  color: var(--color-text-inverse);
}
/* El nav lleva el LOGOTIPO tipográfico (no el iso) — ver framework-ui.md
   sección 4 y "Registro de refinamiento" v3. Es un wordmark ancho (~3.6:1),
   por eso el tamaño se controla por altura (no por ancho, que lo dejaría
   ilegiblemente fino) — el ancho sigue el aspect-ratio real del SVG. */
.nav__logo {
  display: block;
  height: clamp(1.1rem, 0.85rem + 1.1vw, 1.75rem);
}
.nav__logo svg {
  display: block;
  height: 100%;
  width: auto;
}
.nav__menu {
  display: none;
  align-items: center;
  gap: var(--space-lg);
}
.nav__link {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-block: var(--space-xs);
  border-bottom: var(--line-thickness) solid transparent;
  transition: border-color var(--transition-feedback);
}
.nav__link:hover,
.nav__link:focus-visible,
.nav__link[aria-current="page"] {
  border-color: currentColor;
}
/* Declaración base ANTES del media query de desktop a propósito: a igual
   especificidad, la @media (min-width: 64em) más abajo debe ganar por orden
   de cascada y ocultar el hamburger en desktop. El orden inverso (bug
   detectado en QA visual: hamburger visible junto al menú completo a
   1200px) hacía que display:flex de esta regla base ganara siempre. */
.hamburger {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(4px, 0.5vw, 6px);
  width: var(--icon-l);
  height: var(--icon-l);
}
@media (min-width: 64em) {
  .nav__menu {
    display: flex;
  }
  .hamburger {
    display: none;
  }
}
.hamburger__line {
  display: block;
  height: 1px;
  background: currentColor;
  transition:
    transform var(--transition-feedback),
    opacity var(--transition-feedback);
}
.hamburger--active .hamburger__line:nth-child(1) {
  transform: rotate(45deg) translate(5px, 5px);
}
.hamburger--active .hamburger__line:nth-child(2) {
  opacity: 0;
}
.hamburger--active .hamburger__line:nth-child(3) {
  transform: rotate(-45deg) translate(7px, -6px);
}
.nav__mobile {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay-ui);
  background: var(--nahuen-cream);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: var(--space-lg);
  padding-inline: var(--space-section-x);
  transform: translateX(100%);
  /* visibility se retrasa hasta el final de la transición al cerrar (y se
     restaura de inmediato al abrir) — cerrado, los 5 links dejan de estar en
     el tab-order y en el árbol de accesibilidad (hallazgo QA: sin esto, un
     usuario de teclado tabulaba por links invisibles fuera de pantalla). */
  visibility: hidden;
  transition:
    transform var(--transition-interactive),
    visibility 0s var(--duration-interactive);
}
.nav__mobile--open {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--transition-interactive);
}
.nav__mobile .nav__link {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--text-h3);
  text-transform: none;
  letter-spacing: 0;
}
.body-lock {
  overflow: hidden;
}

/* ============================================================
   13. HERO EDITORIAL / MONUMENTAL
   Exclusivo de Home y Single:Campana (direccion-arte.md, sección 9 y 27).
   Entrelazado de capas resuelto por composición discreta por rango de
   dispositivo — ver motion-system.md para la estrategia responsive completa.
   ============================================================ */
.hero-monumental {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding-block: var(--space-section-narrative);
  padding-inline: var(--space-section-x);
}
.hero-monumental__stage {
  position: relative;
  display: grid;
  place-items: center;
  text-align: center;
  max-width: 64rem;
}
.hero-monumental__title {
  position: relative;
  z-index: var(--z-text);
}
/* Estado inicial de la animación de entrada se fija exclusivamente vía JS
   (gsap.set/gsap.from) — NUNCA opacity:0 en CSS (direccion-arte.md, sección
   22, "Restricciones de performance del hero"). Este framework no oculta
   el hero por defecto. */
.hero-monumental__cutout {
  position: absolute;
  z-index: var(--z-cutout);
  max-width: min(60%, 28rem);
  pointer-events: none;
  filter: var(--shadow-cutout);
}
.hero-monumental__cutout--back {
  z-index: 0;
}
.hero-monumental__overlay {
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: -10%;
  z-index: var(--z-texture);
  width: var(--overlay-scale-hero);
  opacity: 0.07;
  pointer-events: none;
  color: var(--nahuen-bordo);
}
.hero-monumental__cta-group {
  position: absolute;
  inset-block-end: var(--space-xl);
  inset-inline: var(--space-section-x);
  display: flex;
  justify-content: space-between;
  gap: var(--space-md);
  z-index: var(--z-text);
}
@media (max-width: 48em) {
  .hero-monumental__cta-group {
    position: static;
    flex-direction: column;
    margin-top: var(--space-xl);
  }
  .hero-monumental__cutout {
    position: static;
    margin-inline: auto;
    margin-top: var(--space-lg);
  }
  /* Mobile: cutout solo detrás del texto, sin capa frontal (direccion-arte.md,
     "Estrategia de responsive para el entrelazado tipográfico", sección 22) */
  .hero-monumental__cutout--front {
    display: none;
  }
}

/* ============================================================
   14. BOTONES Y CTA
   Cero relleno por defecto, contorno ultradelgado, mayúsculas + tracking.
   El "grito" del CTA es tipográfico/posicional, nunca cromático/volumétrico.
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding-block: var(--space-sm);
  padding-inline: var(--space-lg);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: transparent;
  border: var(--line-thickness) solid currentColor;
  border-radius: var(--radius);
  color: var(--color-text);
  transition:
    background var(--transition-interactive),
    color var(--transition-interactive);
}
.btn:hover,
.btn:focus-visible {
  background: var(--color-text);
  color: var(--color-background);
}
.btn--inverse {
  color: var(--color-text-inverse);
}
.btn--inverse:hover,
.btn--inverse:focus-visible {
  background: var(--color-text-inverse);
  color: var(--nahuen-bordo);
}
.btn--attention {
  color: var(--color-attention);
}
.btn--attention:hover,
.btn--attention:focus-visible {
  background: var(--color-attention);
  color: var(--color-text-inverse);
}
.cta-cluster {
  display: flex;
  gap: var(--space-md);
  flex-wrap: wrap;
}

/* ============================================================
   15. CARDS FANTASMA / GRIDS DE CATÁLOGO
   Sin fondo propio, sin sombra, sin borde de caja — separadas por línea
   fina o espacio negativo. El producto insignia NUNCA vive en una card
   tradicional (anti-regla 3) — ver .cutout más abajo.
   ============================================================ */
.card-ghost {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  border-top: var(--line-thickness) solid
    color-mix(in srgb, var(--color-text) 15%, transparent);
  padding-top: var(--space-md);
}
.card-ghost__image {
  aspect-ratio: 4 / 5;
  object-fit: cover;
}
.card-ghost__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--text-h3);
  /* Fix C (ronda de referencias 2026-07-05, analisis-visual.md sección 8):
     altura reservada de 2 líneas — un título más largo que el resto de la
     fila no puede desalinear la card contigua. -webkit-line-clamp funciona
     en todos los motores actuales (Chrome/Firefox/Safari) pese al prefijo. */
  min-height: 2.4em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-ghost__text {
  font-family: var(--font-body);
  /* Fix B (ronda de referencias 2026-07-05): tier chico — texto repetido de
     card nunca comparte tamaño con la bajada de hero ni la intro de bloque
     (--text-body-lg queda exclusivo de esos dos roles). Ver --text-body-sm. */
  font-size: var(--text-body-sm);
  line-height: 1.6;
  max-inline-size: var(--measure-card);
  /* Texto de cuerpo real → tinta completa, nunca --color-text-muted (hallazgo
     del panel: direccion-arte.md sección 15 prohíbe gris lavado en texto de
     cuerpo). */
  color: var(--color-text);
  /* Fix C: presupuesto de 3 líneas — nunca por longitud orgánica de texto
     (analisis-visual.md sección 8/14: "Redbrick Coffee y Crumb Theory nunca
     dejan un card más alto que otro por causa del largo del texto"). */
  min-height: 4.8em;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-ghost__tag {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nahuen-bordo-detalle);
}
/* Módulo insignia — prominencia real, no solo "primero en el grid" */
.card-ghost--insignia .card-ghost__title {
  font-size: var(--text-h2);
}
.card-ghost--insignia .card-ghost__image {
  aspect-ratio: 3 / 2;
}
/* Cuando el módulo insignia no tiene fotografía real todavía (sin excepción,
   nunca un bloque con texto de debug — direccion-arte.md sección 21/23,
   anti-regla 17): superficie plana de un tono del sistema, cero label, cero
   borde punteado. Se lee como decisión de diseño ("superficie en espera"),
   no como error. Sustituye a cualquier placeholder con texto en producción;
   el único placeholder CON etiqueta que sobrevive en el sistema es el
   documentado en la demo (Fase 7, sección "Sistema") como referencia. */
.media-pending {
  background: color-mix(in srgb, var(--nahuen-bordo) 10%, var(--nahuen-cream));
}

/* Encabezado de bloque — kicker izq. + CTA-link der. (Pattern nuevo, Fix G,
   ronda de referencias 2026-07-05). analisis-visual.md sección 8/11/14:
   Redbrick Coffee, "Blends ... Shop blends →" — estructura editorial de dos
   columnas en vez de un kicker centrado solo. Aplica en Archive, hubs de
   línea y bloques de catálogo destacado en Home (Sweet Bakery/Shop en esta
   demo). La regla horizontal es SIEMPRE --line-thickness (nunca más gruesa
   — analisis-visual.md sección 12, "qué puede quedar cutre si se copia
   mal"). El kicker (.line-id--kicker) vive dentro sin cambios de tamaño. */
.section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block-end: var(--space-sm);
  border-bottom: var(--line-thickness) solid
    color-mix(in srgb, var(--color-text) 20%, transparent);
}
.section-header--on-dark {
  border-bottom-color: color-mix(
    in srgb,
    var(--color-text-inverse) 25%,
    transparent
  );
}

/* CTA-link de bajo compromiso — variante "link + flecha" sin caja de
   contorno (analisis-visual.md sección 8: L'Essence du Rouge, "LEARN MORE").
   No sustituye a .btn (compromiso alto, contorno); es la opción para
   encabezados de bloque y "ver más" dentro de una card. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-bottom: var(--line-thickness) solid transparent;
  transition: border-color var(--transition-feedback);
}
.link-arrow:hover,
.link-arrow:focus-visible {
  border-color: currentColor;
}
.link-arrow__arrow {
  display: inline-block;
  transition: transform var(--transition-feedback);
}
.link-arrow:hover .link-arrow__arrow,
.link-arrow:focus-visible .link-arrow__arrow {
  transform: translateX(3px);
}

/* ============================================================
   16. IDENTIFICADORES DE LÍNEA DE NEGOCIO
   Composición tipográfica (Beaufort caps + tracking), NUNCA sellos ni
   imágenes (direccion-arte.md, sección 16). Dos tiers, siempre por debajo
   del H1 real de la página.
   Default ACTUALIZADO (decisión del usuario, feedback Agentation
   2026-07-05): SOLO tipográfico, sin isologo — .line-id__iso queda como
   clase reservada/opcional (no instanciada en ningún template actual) por
   si una futura variante puntual la necesitara; no se elimina del sistema
   porque no rompe nada mantenerla sin uso, pero el marcado por defecto de
   .line-id ya no incluye el <svg>. Ver framework-ui.md sección 4 y regla
   global de iconografía (máx. 1 iso como marca de agua por página, solo en
   cierre/footer bordó — nunca en un kicker repetido en cada bloque).
   ============================================================ */
.line-id {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}
.line-id__iso {
  display: block;
  flex-shrink: 0;
}
.line-id__text {
  font-family: var(--font-heading);
  font-weight: 700;
  text-transform: uppercase;
}
.line-id--kicker {
  font-size: var(--text-kicker);
}
.line-id--kicker .line-id__text {
  letter-spacing: 0.1em;
}
.line-id--kicker .line-id__iso {
  width: var(--text-kicker);
  height: var(--text-kicker);
}
.line-id--header {
  font-size: var(--text-line-header);
}
.line-id--header .line-id__text {
  letter-spacing: 0.08em;
}
.line-id--header .line-id__iso {
  width: var(--text-line-header);
  height: var(--text-line-header);
}
.line-id--on-bordo {
  color: var(--color-text-inverse);
}
/* Apilado vertical solo en mobile si el ancho no alcanza (direccion-arte 16) */
@media (max-width: 30em) {
  .line-id--stack-mobile {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-xs);
  }
}

/* ============================================================
   17. ICONOGRAFÍA — overlay compositivo + funcional
   Rol prioritario: overlay/textura de marca. Rol secundario: ícono
   funcional protagonista con magnetismo (ver motion-system.css/js).
   SVG inline obligatorio (sprite <symbol> + <use> en producción, Fase 8/9)
   — nunca <img> para producción final. Reglas de color por fondo y límites
   de opacidad: direccion-arte.md, sección 20.
   ============================================================ */
.icon-overlay {
  position: absolute;
  pointer-events: none;
  z-index: var(--z-texture);
  color: var(--nahuen-bordo);
}
.icon-overlay svg {
  width: 100%;
  height: auto;
  display: block;
}
.icon-overlay--on-dark {
  color: var(--nahuen-cream);
}
/* Variantes por tipo de sección — escala + opacidad por defecto de la tabla
   canónica (direccion-arte.md sección 20). Cada instancia puede afinar
   --icon-overlay-opacity dentro del rango documentado. */
.icon-overlay--hero {
  width: var(--overlay-scale-hero);
  opacity: var(--icon-overlay-opacity, 0.07);
}
.icon-overlay--impact {
  width: var(--overlay-scale-impact);
  opacity: var(--icon-overlay-opacity, 0.09);
}
.icon-overlay--pattern {
  width: var(--overlay-scale-pattern);
  opacity: var(--icon-overlay-opacity, 0.05);
}
.icon-overlay--transition {
  width: var(--overlay-scale-transition);
  opacity: var(--icon-overlay-opacity, 0.1);
}
.icon-overlay--watermark {
  width: var(--overlay-scale-watermark);
  opacity: var(--icon-overlay-opacity, 0.11);
}
/* Modificadores de posición — utilidades puntuales de ubicación */
.icon-overlay--corner-br {
  inset-block-end: 0;
  inset-inline-end: 0;
}
.icon-overlay--corner-tl {
  inset-block-start: 0;
  inset-inline-start: 0;
}
.icon-overlay--center {
  inset: 0;
  margin: auto;
}
.icon-overlay--bleed-edge {
  inset-block-end: -8%;
  inset-inline-start: -5%;
}

/* Ícono funcional protagonista — 100% opacidad, tamaño real, magnetismo al
   cursor (rol A, direccion-arte.md sección 20). Un solo ícono por módulo. */
.icon-functional {
  display: inline-block;
  width: var(--icon-functional);
  height: var(--icon-functional);
  color: var(--nahuen-bordo);
}
.icon-functional--on-dark {
  color: var(--nahuen-cream);
}
.icon-functional svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* ============================================================
   18. CUTOUTS / IMÁGENES
   Producto insignia SIEMPRE cut-out flotante, nunca en caja rectangular con
   fondo propio (anti-regla 3). Bleed acotado a máx. 15% del ancho del
   contenedor (direccion-arte.md, sección 21) — .section ya aplica
   overflow-x:clip para evitar scroll horizontal en mobile.
   ============================================================ */
.cutout {
  position: relative;
  z-index: var(--z-cutout);
  max-width: 100%;
  filter: var(--shadow-cutout);
}
.cutout--bleed-right {
  margin-inline-end: clamp(-15%, -8vw, -2rem);
}
.cutout--bleed-left {
  margin-inline-start: clamp(-15%, -8vw, -2rem);
}
.cutout--bleed-bottom {
  margin-block-end: clamp(-15%, -8vw, -2rem);
}
.cutout--oblique {
  transform: rotate(-4deg);
}

/* Banda de foto real a sangre completa — nuevo componente (evolución
   sistémica, feedback Agentation 2026-07-05: "no pusiste fotos, solo
   recuadros"). Foto de producto en primer plano como fondo + velo de marca
   (NUNCA gradiente decorativo, anti-regla 9 — tinte plano de --nahuen-bordo
   a opacidad fija) para que el texto en --color-text-inverse cumpla
   contraste AA/AAA sobre cualquier foto. background-image se define inline
   por instancia (contenido real, no un token del sistema). */
.photo-band {
  position: relative;
  min-height: clamp(16rem, 11rem + 20vw, 26rem);
  display: flex;
  align-items: flex-end;
  background-size: cover;
  background-position: center;
  color: var(--color-text-inverse);
}
.photo-band__overlay {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--nahuen-bordo) 55%, transparent);
}
.photo-band__content {
  position: relative;
  z-index: var(--z-text);
  padding: var(--space-xl) var(--space-section-x);
  max-width: var(--measure-reading);
}

.aspect-16-9 {
  aspect-ratio: 16 / 9;
}
.aspect-4-3 {
  aspect-ratio: 4 / 3;
}
.aspect-1-1 {
  aspect-ratio: 1 / 1;
}
.aspect-3-2 {
  aspect-ratio: 3 / 2;
}
.aspect-3-4 {
  aspect-ratio: 3 / 4;
}
.object-cover {
  object-fit: cover;
}
.object-contain {
  object-fit: contain;
}

/* ============================================================
   19. FORMULARIOS — "cuaderno editorial"
   Sin caja completa, línea inferior únicamente, cero border-radius, cero
   overlay decorativo (direccion-arte.md, sección 17 y anti-reglas de motion).
   ============================================================ */
.form-field {
  position: relative;
  margin-block-end: var(--space-lg);
}
.form-field__input,
.form-field__textarea {
  width: 100%;
  padding-block: var(--space-sm);
  padding-inline: 0;
  font-family: var(--font-body);
  font-size: var(--text-body);
  background: transparent;
  border: none;
  border-bottom: var(--line-thickness) solid var(--color-text);
  border-radius: var(--radius);
  color: var(--color-text);
  /* box-shadow en vez de border-width: evita animar una propiedad de layout
     (frontend-guidelines, "anima solo opacity/transform" — box-shadow es
     paint-only, no reflow). */
  transition:
    border-color var(--transition-feedback),
    box-shadow var(--transition-feedback);
}
.form-field__textarea {
  resize: vertical;
  min-height: 6rem;
}
.form-field__input:focus,
.form-field__textarea:focus {
  outline: none;
  border-color: var(--nahuen-bordo);
  /* Simula el engrosamiento a 2px sumando 1px vía box-shadow debajo del
     border-bottom de 1px existente, sin animar border-width. */
  box-shadow: 0 1px 0 0 var(--nahuen-bordo);
}
.form-field__label {
  position: absolute;
  inset-block-start: var(--space-sm);
  inset-inline-start: 0;
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--color-text-muted);
  pointer-events: none;
  transform-origin: left top;
  /* Solo transform: escalar el label en vez de animar font-size (propiedad
     de layout). */
  transition: transform var(--transition-feedback);
}
.form-field__input:focus + .form-field__label,
.form-field__input:not(:placeholder-shown) + .form-field__label,
.form-field__textarea:focus + .form-field__label,
.form-field__textarea:not(:placeholder-shown) + .form-field__label {
  /* scale(0.78) aproxima la razón --text-caption/--text-body en el techo de
     la escala (0.875rem/1.125rem ≈ 0.78) sin animar font-size. */
  transform: translateY(-1.4rem) scale(0.78);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.form-field.is-error .form-field__input,
.form-field.is-error .form-field__textarea {
  border-color: var(--color-error);
}
.form-field.is-success .form-field__input,
.form-field.is-success .form-field__textarea {
  border-color: var(--color-success);
}
.form-field__message {
  display: block;
  margin-top: var(--space-xs);
  font-size: var(--text-caption);
  color: var(--color-error);
}
.form-field__input:disabled,
.form-field__textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Custom checkbox/radio — decisión de marca: el radio también queda
   cuadrado (cero radius sin excepción, incluso donde el default del
   navegador es circular — anti-regla 2, "incluso sutil"). */
.form-check {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  cursor: pointer;
}
.form-check__input {
  appearance: none;
  width: 1.1em;
  height: 1.1em;
  border: var(--line-thickness) solid var(--color-text);
  border-radius: var(--radius);
  background: transparent;
  flex-shrink: 0;
  transition:
    background var(--transition-feedback),
    border-color var(--transition-feedback);
}
.form-check__input:checked {
  background-color: var(--nahuen-bordo);
  border-color: var(--nahuen-bordo);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23FDFBF7'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1z'/%3E%3C/svg%3E");
  background-size: 70%;
  background-position: center;
  background-repeat: no-repeat;
}
.form-check__input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.form-check__label {
  font-size: var(--text-body);
}

/* Filtros/paginación — mismo lenguaje "cuaderno editorial" (direccion-arte,
   Archive, sección 27): sin caja, separador de línea fina, sin chips de color. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  border-bottom: var(--line-thickness) solid
    color-mix(in srgb, var(--color-text) 20%, transparent);
  padding-block-end: var(--space-sm);
}
.filter-bar__item {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  padding-block-end: var(--space-xs);
  /* Línea fina (--line-thickness) en vez de 2px sólido — mantiene el
     registro "cuaderno editorial" también en el estado activo del filtro. */
  border-bottom: var(--line-thickness) solid transparent;
  transition:
    color var(--transition-feedback),
    border-color var(--transition-feedback);
}
.filter-bar__item[aria-current="true"],
.filter-bar__item:hover {
  color: var(--color-text);
  border-color: var(--nahuen-bordo);
}
/* Filtro activo — Poppins Medium (direccion-arte.md, sección 27, Archive) */
.filter-bar__item[aria-current="true"] {
  font-weight: 500;
}

/* ============================================================
   20. BADGES / ALERTS / SKELETON / EMPTY STATE / FAQ
   ============================================================ */
.badge {
  display: inline-flex;
  align-items: center;
  padding-block: var(--space-xs);
  padding-inline: var(--space-sm);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: var(--radius);
  border: var(--line-thickness) solid var(--nahuen-bordo-detalle);
  color: var(--nahuen-bordo-detalle);
}
.badge--filled {
  background: var(--nahuen-bordo-detalle);
  color: var(--color-text-inverse);
  border-color: var(--nahuen-bordo-detalle);
}
.badge--attention {
  border-color: var(--color-attention);
  color: var(--color-attention);
}
.badge--s {
  font-size: var(--text-caption);
  padding-block: 2px;
}
.badge--l {
  padding-block: var(--space-sm);
  padding-inline: var(--space-md);
}

.alert {
  display: flex;
  gap: var(--space-sm);
  padding-block: var(--space-md);
  padding-inline: var(--space-lg);
  border-radius: var(--radius);
  border-inline-start: 3px solid;
  font-size: var(--text-body);
}
.alert--info {
  /* Rosa (transición), NUNCA Sage: Sage es exclusivo de contenido
     Market/salado (direccion-arte.md sección 15) y este es un componente
     utilitario transversal que puede aparecer en cualquier página, incluida
     Sweet Bakery/Single:Cake — filtrar Sage ahí violaría el territorio de
     color (hallazgo del panel, corregido). */
  background: color-mix(in srgb, var(--nahuen-rosa) 70%, var(--nahuen-cream));
  border-color: var(--nahuen-bordo);
  color: var(--color-text);
}
.alert--success {
  background: color-mix(in srgb, var(--color-success) 12%, var(--nahuen-cream));
  border-color: var(--color-success);
  color: var(--color-success);
}
.alert--warning {
  background: color-mix(in srgb, var(--color-warning) 12%, var(--nahuen-cream));
  border-color: var(--color-warning);
  color: var(--color-warning);
}
.alert--error {
  background: color-mix(in srgb, var(--color-error) 12%, var(--nahuen-cream));
  border-color: var(--color-error);
  color: var(--color-error);
}

/* Pulso de opacidad sobre fondo plano — NO gradiente (anti-regla 9, "cero
   sombra/gradiente decorativo sin excepción documentada"; el shimmer
   original era un linear-gradient animado, corregido en refinamiento
   post-panel). Colores de marca (Rosa), solo opacity. */
.skeleton {
  background: var(--nahuen-rosa);
  animation: skeleton-pulse 1.5s ease-in-out infinite;
  border-radius: var(--radius);
}
@keyframes skeleton-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--space-2xl);
  gap: var(--space-sm);
}
.empty-state__icon {
  width: var(--icon-xl);
  height: var(--icon-xl);
  color: var(--color-text-muted);
}
.empty-state__title {
  font-family: var(--font-heading);
  font-size: var(--text-h3);
}
.empty-state__description {
  /* Texto de cuerpo real → tinta completa, no muted (ver .card-ghost__text). */
  color: var(--color-text);
}

/* FAQ acordeón — cuaderno editorial, sin decoración (direccion-arte 17) */
.faq-item {
  border-top: var(--line-thickness) solid
    color-mix(in srgb, var(--color-text) 15%, transparent);
}
.faq-item__question {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  padding-block: var(--space-md);
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--text-body-lg);
  text-align: start;
}
/* El "+" debe leerse como CONTROL, no como imagen suelta (hallazgo
   Agentation 2026-07-05: "¿esta imagen qué es?") — tipografía Poppins,
   tamaño contenido dentro de una caja bordó de línea fina (mismo lenguaje
   "cuaderno editorial" que .btn), nunca texto flotante sin límite visual. */
.faq-item__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--icon-s);
  height: var(--icon-s);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-body-lg);
  line-height: 1;
  color: var(--nahuen-bordo);
  border: var(--line-thickness) solid var(--nahuen-bordo);
  transition: transform var(--transition-feedback);
}
.faq-item[data-open="true"] .faq-item__icon {
  transform: rotate(45deg);
}
/* Técnica grid-template-rows 0fr→1fr: anima la apertura sin animar
   max-height (propiedad de layout con reflow por frame — antes usaba un
   valor "mágico" de 40rem que además distorsionaba la velocidad percibida). */
.faq-item__answer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--transition-interactive);
}
.faq-item[data-open="true"] .faq-item__answer {
  grid-template-rows: 1fr;
}
.faq-item__answer-inner {
  overflow: hidden;
  padding-block-end: var(--space-md);
  /* Texto de cuerpo real → tinta completa, no muted. */
  color: var(--color-text);
  max-width: var(--measure-reading);
}

/* Resumen citable — blockquote editorial (Blog, GEO/AI Overviews) */
.callout-citable {
  border-inline-start: 3px solid var(--nahuen-bordo);
  background: var(--nahuen-rosa);
  padding: var(--space-lg);
  font-family: var(--font-heading);
  font-size: var(--text-body-lg);
  line-height: 1.6;
}

/* Divisor fino */
.divider {
  border: none;
  border-top: var(--line-thickness) solid
    color-mix(in srgb, var(--color-text) 20%, transparent);
}
.divider--on-dark {
  border-top-color: color-mix(
    in srgb,
    var(--color-text-inverse) 30%,
    transparent
  );
}

/* ============================================================
   21. FOOTER — 4 columnas / 2 filas sobre franja Borgoña
   ============================================================ */
.site-footer {
  background: var(--nahuen-bordo);
  color: var(--color-text-inverse);
  padding-block: var(--space-section-utility);
}
/* Tamaño duplicado (hallazgo Agentation 2026-07-05: "está muy chico") —
   logo tipográfico (mismo wordmark del nav, variante blanco), referenciado
   como <img> de archivo real (no inline): color fijo, no necesita
   currentColor. */
.site-footer__logo {
  display: block;
  width: clamp(5rem, 4rem + 4vw, 7rem);
  margin-bottom: var(--space-lg);
  color: var(--color-text-inverse);
}
.site-footer__brand {
  font-family: var(--font-heading);
  font-size: var(--text-h3);
  margin-bottom: var(--space-xl);
  max-width: 32rem;
}
.site-footer__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-xl);
}
@media (max-width: 48em) {
  .site-footer__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
.site-footer__col-title {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-caption);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: var(--space-sm);
  opacity: 0.75;
}
.site-footer__link {
  display: block;
  padding-block: var(--space-xs);
  /* 13px fijos (fix Agentation Home 2026-07-05 #10): los menús del footer
     son navegación utilitaria, no cuerpo de lectura — bajan del tier
     --text-body a un tamaño propio, decisión del cliente. */
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--color-text-inverse);
  opacity: 0.9;
  transition: opacity var(--transition-feedback);
}
.site-footer__link:hover,
.site-footer__link:focus-visible {
  opacity: 1;
  text-decoration: underline;
}
.site-footer__legal {
  margin-top: var(--space-2xl);
  padding-top: var(--space-md);
  border-top: var(--line-thickness) solid
    color-mix(in srgb, var(--color-text-inverse) 25%, transparent);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-sm);
  /* 11px fijos + más muted (fix Agentation Home 2026-07-05 #11):
     Privacy/Terms y el © son la letra chica real del sitio — mucho más
     chicos que la navegación, decisión del cliente. */
  font-size: 0.6875rem;
  letter-spacing: 0.03em;
  opacity: 0.6;
}
/* Los links dentro de la fila legal heredan el tamaño de letra chica (no
   el 13px de los menús) — Privacy Policy / Terms & Conditions. */
.site-footer__legal .site-footer__link {
  display: inline;
  padding: 0;
  font-size: inherit;
}

/* ============================================================
   22. UTILIDADES
   Transversales, documentadas, reutilizables — no reemplazan componentes
   (regla anti-utility-first, ver framework-ui.md).
   ============================================================ */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Skip link y cualquier .sr-only que reciba foco de teclado deben volverse
   visibles (WCAG 2.4.1). Hallazgo QA: el skip link quedaba inalcanzable
   visualmente pese a ser document.activeElement. */
.sr-only:focus,
.sr-only:focus-visible {
  position: fixed;
  inset-block-start: var(--space-sm);
  inset-inline-start: var(--space-sm);
  width: auto;
  height: auto;
  padding: var(--space-sm) var(--space-md);
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
  background: var(--nahuen-cream);
  color: var(--nahuen-bordo);
  border: var(--line-thickness) solid var(--nahuen-bordo);
  z-index: calc(var(--z-overlay-ui) + 1);
}
.text-center {
  text-align: center;
}
.text-start {
  text-align: start;
}

/* No existen utilidades .shadow-sm/md/lg/xl en este proyecto (removidas en
   refinamiento post-panel junto con la escala de tokens — ver sección 5).
   Único uso legítimo de sombra: --shadow-cutout en .cutout. */

.space-y-xs {
  margin-top: var(--space-xs);
}
.space-y-sm {
  margin-top: var(--space-sm);
}
.space-y-md {
  margin-top: var(--space-md);
}
.space-y-lg {
  margin-top: var(--space-lg);
}
.space-y-xl {
  margin-top: var(--space-xl);
}

[data-tooltip] {
  position: relative;
}
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + var(--space-xs));
  left: 50%;
  transform: translateX(-50%);
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-text);
  color: var(--color-background);
  font-size: var(--text-caption);
  border-radius: var(--radius);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-feedback);
}
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
  opacity: 1;
}

/* Animaciones utilitarias base (sin motion narrativo — eso vive en
   motion-system.css). Solo transform/opacity (frontend-guidelines). */
.fade-in {
  animation: fadeIn var(--duration-interactive) var(--ease-feedback);
}
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.slide-up {
  animation: slideUp var(--duration-interactive) var(--ease-feedback);
}
@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(var(--space-md));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.hover-lift {
  transition: transform var(--transition-interactive);
}
.hover-lift:hover {
  transform: translateY(-2px);
}

/* ============================================================
   23. ACCESIBILIDAD — prefers-reduced-motion
   Obligatorio, sin excepción (anti-regla 5 de motion). El !important aquí
   es la única excepción documentada a "evitar !important": debe ganar
   siempre sobre cualquier especificidad de componente por ser una
   preferencia de accesibilidad del sistema operativo del usuario.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: var(--duration-feedback) !important;
    scroll-behavior: auto !important;
  }
  /* El menú móvil no puede seguir desplazándose (translateX) bajo reduced-
     motion — anti-regla 5 de motion exige fade sin desplazamiento o
     desactivar, sin excepción. La regla genérica de arriba solo acorta la
     duración a 200ms, no elimina el desplazamiento; esto lo neutraliza. */
  .nav__mobile {
    transition: none !important;
  }
}

/* ============================================================
   24. MOTION — CSS de motion vive en motion-system.css (archivo separado)
   Justificación (ver motion-system.md, Paso 4): más de 4 clases de estado/
   comportamiento propias (.motion-reveal, .is-visible, .motion-parallax,
   .motion-magnetic, .hero-entangle__layer--*) y timing gobernado desde JS
   (GSAP no interpola clamp() de CSS). Este archivo NO debe recibir clases
   de motion sueltas — toda evolución de motion pasa por motion-system.css.
   ============================================================ */
