
Halo cónico
ProBrillo · CSS
La pieza
Un héroe de perfumería sobre un degradado de malla cálido: cinco radial-gradient cuyas posiciones y colores están registrados con @property, así que se desplazan lentamente con @keyframes de duraciones distintas y nunca se repiten de forma evidente. Encima, un grano SVG feTurbulence en overlay le da textura de papel impreso. Un selector de tres notas (Salida, Corazón y Fondo) cambia la paleta con :has() y la funde en 1,4 segundos: cítrica, rosada o ámbar oscuro, con el texto adaptándose. Todo el efecto ocupa unos 2 KB y no usa ni una etiqueta script. Encaja como fondo de héroe, tarjeta, banda de llamada a la acción o sello en webs de perfumería, cosmética, hoteles, bodegas o estudios creativos. Cambia la paleta en dos líneas para llevarla a azules de mar, verdes de bosque o tierras de arcilla.
Encaja bien en webs de
Antes de copiar
Cambia lo que quieras y copia: el prompt sale ya con el nombre, los colores y los textos de tu cliente. Lo que dejes en blanco se queda como en la demo.
Gratis y entero
Qué trae el prompt, por apartados
Tokens estimados para español (≈3,6 caracteres por token): sirven para orientarte, no son exactos.
# Recrea en un único archivo HTML: Malla de color en CSS puro
Un héroe de perfumería con un degradado de malla vivo, cálido y granulado que respira despacio y cambia de paleta al elegir una nota, hecho solo con CSS: cero JavaScript.
Eres un desarrollador front-end creativo senior. Genera un único `index.html` autocontenido que
reproduzca exactamente la pieza descrita: mismo layout, textos, colores, movimiento e interacción.
HTML, CSS y JS en un solo archivo, sin build ni frameworks. Librerías solo por CDN y en las versiones
indicadas. Todos los valores numéricos de este documento son definitivos: úsalos tal cual.
Responde solo con el archivo completo.
## Qué es
Una página corta para **Maison Aurelle**, una perfumería de autor ficticia de Valmora, que presenta su colonia de primavera «Agua de neroli». Es el escaparate de una técnica: un **degradado de malla** (mesh gradient) construido con cinco `radial-gradient` superpuestos sobre un color base, cuyas posiciones y colores son **propiedades personalizadas registradas con `@property`**. Al estar registradas, el navegador sabe interpolarlas, así que:
- las cinco manchas de color se desplazan con `@keyframes` que animan directamente `--x1`, `--y1`… (porcentajes), cada una con una duración distinta (11, 13, 17, 19 y 23 s, en `alternate`), de modo que el conjunto nunca se repite de forma evidente;
- los colores `--m0`…`--m5` y el color del texto `--tinta` se animan con `transition` al cambiar de paleta: el fundido de una paleta a otra es suave (1,4 s), no un salto.
Encima de la malla hay un **grano** hecho con un SVG `feTurbulence` en línea (data URI) mezclado en `overlay` al 50 %, que le quita el aspecto digital y le da textura de papel impreso.
La interacción es **100 % CSS**: un grupo de radios «Cambia la nota» (Salida, Corazón, Fondo) cambia la paleta del héroe mediante `:has()`. Cada nota de la pirámide olfativa tiene su color: Salida es cítrica y clara (naranja, limón, neroli, hoja), Corazón es floral y rosada (coral, rosa, neroli) y Fondo es oscura y ambarina (cedro, ámbar, noche). En Fondo el texto pasa a crema.
Debajo del héroe hay dos secciones: «La pirámide» (tres tarjetas, cada una con su propia malla animada en la paleta de su nota) y «El taller» (datos de contacto sobre fondo tinta, con un sello circular que también es una malla). **No hay ni una etiqueta `<script>` en todo el archivo.** El núcleo del efecto (las `@property`, el `background` de la malla, los cinco `@keyframes` y el grano) ocupa unos 2 KB.
Tono general: claro, cálido, editorial, de marca de lujo pequeña. Tipografía de revista: un Bodoni de alto contraste para los titulares (con cursivas protagonistas) y una grotesca humanista para el texto.
## Librerías y esqueleto
Sin librerías de JavaScript. Solo dos familias de Google Fonts (las dos tienen ñ, tildes, ¿ y ¡):
- **Bodoni Moda** (variable, ejes `opsz` 6–96 y `wght` 400–700, con cursiva) para titulares, marca, nombres de nota, números y precio.
- **Hanken Grotesk** 400, 500 y 600 para todo lo demás.
Cabecera literal del documento (con el `<style>` de la sección «Código clave» dentro de `<head>`, justo después de estos `<link>`):
```html
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Maison Aurelle · Agua de neroli, colonia N.º 7</title>
<meta name="description" content="Agua de neroli, la colonia de primavera de Maison Aurelle, perfumería de autor en Valmora.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bodoni+Moda:ital,opsz,wght@0,6..96,400..700;1,6..96,400..700&family=Hanken+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* todo el CSS de «Código clave» */
</style>
</head>
```
Nada de imágenes, iconos externos ni scripts. La única imagen es el SVG del grano, en línea como data URI dentro del CSS. La flecha del botón es un SVG en línea.
## Tokens de diseño
Estas son las variables. Las siete primeras (`--m0`…`--m5` y `--tinta`) **no se declaran en `:root` sino con `@property`** (ver «Código clave»), porque tienen que ser animables; aquí se listan como referencia junto con el resto.
```css
/* Paleta «Salida» (la de inicio): registrada con @property */
--m0: #f6ecd9; /* base de la malla: crema de neroli */
--m1: #f39a45; /* naranja */
--m2: #ffd36a; /* limón */
--m3: #fff3dc; /* flor blanca, casi luz */
--m4: #e5704a; /* naranja amarga */
--m5: #b8c888; /* hoja de naranjo */
--tinta: #231a12; /* texto sobre la malla */
:root {
--papel: #f3ebdd; /* fondo de la sección «La pirámide» */
--tinta-fija: #231a12; /* texto sobre papel y fondo de «El taller» */
--crema: #f6eee2; /* texto sobre fondo tinta */
--vaiven: cubic-bezier(.45, .05, .55, .95); /* easing del movimiento de las manchas */
--salida: cubic-bezier(.22, 1, .36, 1); /* easing de transiciones de interfaz */
--display: 'Bodoni Moda', 'Didot', Georgia, serif;
--texto: 'Hanken Grotesk', system-ui, sans-serif;
--margen: clamp(1.25rem, 4vw, 3.5rem);
--grano: url("data:image/svg+xml,…"); /* SVG feTurbulence, literal en «Código clave» */
}
```
Las tres paletas completas (m0 · m1 · m2 · m3 · m4 · m5 · tinta):
| Paleta | m0 (base) | m1 | m2 | m3 | m4 | m5 | tinta |
|---|---|---|---|---|---|---|---|
| Salida | `#f6ecd9` | `#f39a45` | `#ffd36a` | `#fff3dc` | `#e5704a` | `#b8c888` | `#231a12` |
| Corazón | `#f7e2dc` | `#f09a88` | `#f9cbbd` | `#fff7ee` | `#de7f93` | `#f3c178` | `#2a1518` |
| Fondo | `#1a1320` | `#5a2f24` | `#8a5127` | `#2b2140` | `#6e3b25` | `#34463f` | `#f6eee2` |
Colores secundarios fijos: texto secundario sobre papel `#4a3d30`, etiqueta de duración `#5b4a3a`, texto atenuado sobre tinta `#d9c9b2`, filetes sobre tinta `rgba(246, 238, 226, .18)`.
Escala tipográfica:
- Titular del héroe: Bodoni Moda 500, `clamp(4.4rem, 12.4vw, 11.75rem)`, interlineado `.84`, tracking `-.04em`. La segunda línea en cursiva 400, desplazada `.42em` a la derecha.
- H2 de sección: Bodoni Moda 400, `clamp(2.6rem, 6.4vw, 5.6rem)`, interlineado `.95`, tracking `-.035em`; la segunda parte en cursiva.
- Etiquetas (`.etiqueta`): Hanken Grotesk 600, `.72rem`, tracking `.16em`, mayúsculas.
- Texto base: Hanken Grotesk 400, `1rem/1.6`.
## Estructura y contenido
Árbol de la página, con todos los textos literales. Las cursivas indicadas van en `<em>`.
1. **Enlace de salto** «Saltar al contenido» (oculto hasta recibir foco), apunta a `#contenido`.
2. **`<header class="heroe p-salida">`** — alto mínimo `100svh`, rejilla de tres filas (cabecera · centro · pie). Primer hijo: `<div class="malla" aria-hidden="true">` a sangre, detrás de todo.
- **Cabecera**: a la izquierda la marca, «Maison Aurelle» en Bodoni Moda cursiva 500 a 1,65rem y debajo la etiqueta «Perfumería de autor · Valmora». A la derecha la navegación: «La pirámide» (`#piramide`), «El taller» (`#taller`) y un botón de contorno en píldora «Pedir muestra» (`#taller`).
- **Centro** (`id="contenido"`), dos columnas alineadas abajo:
- Izquierda: H1 «Agua de» / «*neroli*» con un superíndice «N.º 7» en etiqueta (Hanken 600, .72rem, tracking .16em) pegado arriba a la derecha de la palabra en cursiva. Entradilla (máx. 34ch): «Una colonia que huele a jardín cerrado en marzo: flor de naranjo recién abierta, piel de limón y un fondo de cedro que se queda tibio en la piel.» Debajo, botón relleno «Descubrir la colonia →» (`#taller`) y al lado el precio: «**68 €**» en Bodoni 1,35rem seguido de «100 ml · IVA incl.».
- Derecha: `<fieldset>` con leyenda «Cambia la nota» y tres opciones (radios con `name="nota"`):
- «1» · «Salida» · «Naranja amarga y limón» (`id="nota-salida"`, marcada por defecto)
- «2» · «Corazón» · «Flor de naranjo y jazmín» (`id="nota-corazon"`)
- «3» · «Fondo» · «Cedro y ámbar gris» (`id="nota-fondo"`)
- **Pie del héroe**: a la izquierda «**Edición de primavera ·** 1.200 frascos numerados» (la parte en negrita se oculta en móvil); a la derecha un enlace «Desliza» (`#piramide`) con una línea vertical de 1 px × 2,6rem que gotea en bucle.
3. **`<main>`**
- **`<section class="piramide" id="piramide">`** sobre `--papel`.
- Cabecera en dos columnas: etiqueta «La pirámide olfativa», H2 «Tres tiempos *en la piel*»; a la derecha el párrafo «Cada perfume cambia mientras lo llevas. Lo hemos compuesto en tres capas, y a cada una le hemos dado su color: así se ve lo que tardarías una tarde en oler.»
- Lista ordenada de tres tarjetas. Cada una: una malla (proporción 4/5, radio 22px, con su paleta) que lleva arriba a la izquierda una etiqueta de tiempo y abajo un número enorme en Bodoni cursiva; debajo, H3, texto y etiqueta de duración.
- «0–15 min» · «1» · **Salida** · «Naranja amarga de huerto, limón de temporada y un golpe de bergamota.» · «Dura hasta 15 minutos»
- «15 min – 3 h» · «2» · **Corazón** · «Flor de naranjo destilada en abril, neroli y jazmín de noche.» · «De 15 minutos a 3 horas»
- «3 h – 8 h» · «3» · **Fondo** · «Cedro del Atlas, ámbar gris y almizcle blanco, cálidos y lentos.» · «Hasta 8 horas en la piel»
- **`<section class="taller" id="taller">`** sobre `--tinta-fija`, texto crema.
- Izquierda: etiqueta «El taller», H2 «Ven a olerla *al taller*», y un sello circular (malla con paleta Corazón) con «N.º 7» en Bodoni cursiva.
- Derecha: lista de definiciones con filetes: «Dirección» → «Avenue Bellevue 42, 10003 Valmora»; «Horario» → «Lunes a sábado, 10:30–14:00 y 17:30–20:30»; «Teléfono» → «+00 000 000 000» (enlace `tel:`); «Email» → «hola@maisonaurelle.com» (enlace `mailto:`). Debajo, la oferta: «68 € IVA incl.» (precio en Bodoni 2,2rem, «IVA incl.» en pequeño) y «Agua de neroli · 100 ml · muestra de 2 ml gratis en tienda».
- Pie: «© 2026 Maison Aurelle · Hecho a mano en Valmora» y «Fondo en CSS puro: cinco degradados y cero JavaScript».
HTML literal del `<body>` (cópialo tal cual):
```html
<body>
<a class="salto" href="#contenido">Saltar al contenido</a>
<header class="heroe p-salida">
<div class="malla" aria-hidden="true"></div>
<div class="cabecera">
<a class="marca" href="#">
<b>Maison Aurelle</b>
<span class="etiqueta">Perfumería de autor · Valmora</span>
</a>
<nav aria-label="Principal">
<ul>
<li><a href="#piramide">La pirámide</a></li>
<li><a href="#taller">El taller</a></li>
<li><a class="boton-linea" href="#taller">Pedir muestra</a></li>
</ul>
</nav>
</div>
<div class="centro" id="contenido">
<div>
<h1 class="titular">Agua de <em>neroli<sup>N.º 7</sup></em></h1>
<p class="entradilla">Una colonia que huele a jardín cerrado en marzo: flor de naranjo recién abierta, piel de limón y un fondo de cedro que se queda tibio en la piel.</p>
<div class="acciones">
<a class="boton" href="#taller">Descubrir la colonia
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M1 8h13M9 3l5 5-5 5" stroke="currentColor" stroke-width="1.5"/></svg>
</a>
<p class="precio"><strong>68 €</strong>100 ml · IVA incl.</p>
</div>
</div>
<fieldset class="notas">
<legend class="etiqueta">Cambia la nota</legend>
<div class="notas-lista">
<label class="nota">
<input type="radio" name="nota" id="nota-salida" checked>
<span class="num">1</span><span class="nombre">Salida</span>
<span class="detalle">Naranja amarga y limón</span>
</label>
<label class="nota">
<input type="radio" name="nota" id="nota-corazon">
<span class="num">2</span><span class="nombre">Corazón</span>
<span class="detalle">Flor de naranjo y jazmín</span>
</label>
<label class="nota">
<input type="radio" name="nota" id="nota-fondo">
<span class="num">3</span><span class="nombre">Fondo</span>
<span class="detalle">Cedro y ámbar gris</span>
</label>
</div>
</fieldset>
</div>
<div class="pie-heroe">
<p class="edicion" style="margin:0"><b>Edición de primavera · </b>1.200 frascos numerados</p>
<a class="desliza" href="#piramide"><span>Desliza</span><i aria-hidden="true"></i></a>
</div>
</header>
<main>
<section class="piramide" id="piramide" aria-labelledby="t-piramide">
<div class="piramide-cabeza">
<div>
<p class="etiqueta" style="margin:0">La pirámide olfativa</p>
<h2 id="t-piramide">Tres tiempos <em>en la piel</em></h2>
</div>
<p>Cada perfume cambia mientras lo llevas. Lo hemos compuesto en tres capas, y a cada una le hemos dado su color: así se ve lo que tardarías una tarde en oler.</p>
</div>
<ol class="tarjetas">
<li class="tarjeta">
<div class="malla p-salida" aria-hidden="true"><span class="etiqueta">0–15 min</span><span class="grande">1</span></div>
<h3>Salida</h3>
<p>Naranja amarga de huerto, limón de temporada y un golpe de bergamota.</p>
<span class="dura etiqueta">Dura hasta 15 minutos</span>
</li>
<li class="tarjeta">
<div class="malla p-corazon" aria-hidden="true"><span class="etiqueta">15 min – 3 h</span><span class="grande">2</span></div>
<h3>Corazón</h3>
<p>Flor de naranjo destilada en abril, neroli y jazmín de noche.</p>
<span class="dura etiqueta">De 15 minutos a 3 horas</span>
</li>
<li class="tarjeta">
<div class="malla p-fondo" aria-hidden="true"><span class="etiqueta">3 h – 8 h</span><span class="grande">3</span></div>
<h3>Fondo</h3>
<p>Cedro del Atlas, ámbar gris y almizcle blanco, cálidos y lentos.</p>
<span class="dura etiqueta">Hasta 8 horas en la piel</span>
</li>
</ol>
</section>
<section class="taller" id="taller" aria-labelledby="t-taller">
<div class="taller-rejilla">
<div>
<p class="etiqueta" style="margin:0">El taller</p>
<h2 id="t-taller">Ven a olerla <em>al taller</em></h2>
<div class="sello malla p-corazon" aria-hidden="true"><span>N.º 7</span></div>
</div>
<div>
<dl class="datos">
<div><dt>Dirección</dt><dd>Avenue Bellevue 42, 10003 Valmora</dd></div>
<div><dt>Horario</dt><dd>Lunes a sábado, 10:30–14:00 y 17:30–20:30</dd></div>
<div><dt>Teléfono</dt><dd><a href="tel:+00 000 000 000">+00 000 000 000</a></dd></div>
<div><dt>Email</dt><dd><a href="mailto:hola@maisonaurelle.com">hola@maisonaurelle.com</a></dd></div>
</dl>
<div class="oferta">
<strong>68 € <small>IVA incl.</small></strong>
<small>Agua de neroli · 100 ml · muestra de 2 ml gratis en tienda</small>
</div>
</div>
</div>
<footer class="creditos">
<span>© 2026 Maison Aurelle · Hecho a mano en Valmora</span>
<span>Fondo en CSS puro: cinco degradados y cero JavaScript</span>
</footer>
</section>
</main>
</body>
```
## Movimiento
Todo el movimiento es CSS. No hay animaciones de entrada: la página aparece ya compuesta y la vida la pone la malla.
| Elemento | Propiedad | De → a | Duración | Easing | Retardo | Disparador |
|---|---|---|---|---|---|---|
| Mancha 1 (`--x1`, `--y1`) | posición | 14% 20% → 42% 6% → 26% 46% | 13 s, `alternate`, infinito | `--vaiven` | 0 | carga |
| Mancha 2 (`--x2`, `--y2`) | posición | 78% 16% → 56% 34% → 92% 44% | 17 s, `alternate`, infinito | `--vaiven` | 0 | carga |
| Mancha 3 (`--x3`, `--y3`) | posición | 58% 56% → 34% 70% → 70% 28% | 11 s, `alternate`, infinito | `--vaiven` | 0 | carga |
| Mancha 4 (`--x4`, `--y4`) | posición | 20% 88% → 48% 96% → 6% 62% | 19 s, `alternate`, infinito | `--vaiven` | 0 | carga |
| Mancha 5 (`--x5`, `--y5`) | posición | 90% 82% → 70% 60% → 96% 98% | 23 s, `alternate`, infinito | `--vaiven` | 0 | carga |
| Tarjeta 2 (sus 5 manchas) | idem | idem | idem | idem | −4 s, −9 s, −2 s, −12 s, −7 s | carga |
| Tarjeta 3 (sus 5 manchas) | idem | idem | idem | idem | −8 s, −3 s, −6 s, −5 s, −15 s | carga |
| Héroe | `--m0`…`--m5`, `--tinta` | paleta actual → paleta elegida | 1,4 s | `--salida` | 0 | cambio de radio |
| Opción de nota | fondo, color, borde | contorno → relleno tinta | .6 s | `--salida` | 0 | `:checked` |
| Botón relleno | `transform` | 0 → `translateY(-2px)`; flecha `translateX(3px)` | .5 s | `--salida` | 0 | hover |
| Enlaces de nav | subrayado (`background-size`) | 0 → 100% × 1px | .5 s | `--salida` | 0 | hover |
| «Pedir muestra» | fondo / color | transparente → tinta, texto `--m0` | .4 s | `--salida` | 0 | hover |
| Línea de «Desliza» | `scaleY` | 0 → 1 (origen arriba) y 1 → 0 (origen abajo) | 2,4 s, infinito | `--salida` | 0 | carga |
Las manchas del héroe y de las tarjetas usan las mismas animaciones; los retardos negativos solo desincronizan las tarjetas para que no se vean iguales.
## Código clave
Este es el CSS completo del `<style>`. Es definitivo: cópialo literal. Lo esencial está en los bloques 1 y 2: sin `@property` los `@keyframes` no pueden interpolar `--x1`… ni la `transition` puede fundir los colores (sin registro saltarían de golpe).
```css
/* ---------- 1. Propiedades registradas: lo que hace animable la malla ---------- */
@property --m0 { syntax: '<color>'; inherits: true; initial-value: #f6ecd9; }
@property --m1 { syntax: '<color>'; inherits: true; initial-value: #f39a45; }
@property --m2 { syntax: '<color>'; inherits: true; initial-value: #ffd36a; }
@property --m3 { syntax: '<color>'; inherits: true; initial-value: #fff3dc; }
@property --m4 { syntax: '<color>'; inherits: true; initial-value: #e5704a; }
@property --m5 { syntax: '<color>'; inherits: true; initial-value: #b8c888; }
@property --tinta { syntax: '<color>'; inherits: true; initial-value: #231a12; }
@property --x1 { syntax: '<percentage>'; inherits: false; initial-value: 14%; }
@property --y1 { syntax: '<percentage>'; inherits: false; initial-value: 20%; }
@property --x2 { syntax: '<percentage>'; inherits: false; initial-value: 78%; }
@property --y2 { syntax: '<percentage>'; inherits: false; initial-value: 16%; }
@property --x3 { syntax: '<percentage>'; inherits: false; initial-value: 58%; }
@property --y3 { syntax: '<percentage>'; inherits: false; initial-value: 56%; }
@property --x4 { syntax: '<percentage>'; inherits: false; initial-value: 20%; }
@property --y4 { syntax: '<percentage>'; inherits: false; initial-value: 88%; }
@property --x5 { syntax: '<percentage>'; inherits: false; initial-value: 90%; }
@property --y5 { syntax: '<percentage>'; inherits: false; initial-value: 82%; }
:root {
--papel: #f3ebdd;
--tinta-fija: #231a12;
--crema: #f6eee2;
--vaiven: cubic-bezier(.45, .05, .55, .95);
--salida: cubic-bezier(.22, 1, .36, 1);
--display: 'Bodoni Moda', 'Didot', Georgia, serif;
--texto: 'Hanken Grotesk', system-ui, sans-serif;
--margen: clamp(1.25rem, 4vw, 3.5rem);
--grano: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
}
/* Paletas: una por nota de la pirámide olfativa */
.p-salida { --m0: #f6ecd9; --m1: #f39a45; --m2: #ffd36a; --m3: #fff3dc; --m4: #e5704a; --m5: #b8c888; --tinta: #231a12; }
.p-corazon { --m0: #f7e2dc; --m1: #f09a88; --m2: #f9cbbd; --m3: #fff7ee; --m4: #de7f93; --m5: #f3c178; --tinta: #2a1518; }
.p-fondo { --m0: #1a1320; --m1: #5a2f24; --m2: #8a5127; --m3: #2b2140; --m4: #6e3b25; --m5: #34463f; --tinta: #f6eee2; }
/* ---------- 2. La malla ---------- */
.malla {
position: relative;
isolation: isolate;
overflow: hidden;
background:
radial-gradient(46% 60% at var(--x1) var(--y1), var(--m1), transparent 72%),
radial-gradient(50% 56% at var(--x2) var(--y2), var(--m2), transparent 70%),
radial-gradient(40% 48% at var(--x3) var(--y3), var(--m3), transparent 68%),
radial-gradient(58% 66% at var(--x4) var(--y4), var(--m4), transparent 74%),
radial-gradient(46% 52% at var(--x5) var(--y5), var(--m5), transparent 70%),
var(--m0);
animation:
b1 13s var(--vaiven) infinite alternate,
b2 17s var(--vaiven) infinite alternate,
b3 11s var(--vaiven) infinite alternate,
b4 19s var(--vaiven) infinite alternate,
b5 23s var(--vaiven) infinite alternate;
}
.malla::after {
content: '';
position: absolute;
inset: 0;
background: var(--grano);
background-size: 240px;
mix-blend-mode: overlay;
opacity: .5;
pointer-events: none;
}
@keyframes b1 { 0% { --x1: 14%; --y1: 20%; } 50% { --x1: 42%; --y1: 6%; } 100% { --x1: 26%; --y1: 46%; } }
@keyframes b2 { 0% { --x2: 78%; --y2: 16%; } 50% { --x2: 56%; --y2: 34%; } 100% { --x2: 92%; --y2: 44%; } }
@keyframes b3 { 0% { --x3: 58%; --y3: 56%; } 50% { --x3: 34%; --y3: 70%; } 100% { --x3: 70%; --y3: 28%; } }
@keyframes b4 { 0% { --x4: 20%; --y4: 88%; } 50% { --x4: 48%; --y4: 96%; } 100% { --x4: 6%; --y4: 62%; } }
@keyframes b5 { 0% { --x5: 90%; --y5: 82%; } 50% { --x5: 70%; --y5: 60%; } 100% { --x5: 96%; --y5: 98%; } }
/* ---------- 3. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
margin: 0;
background: var(--papel);
color: var(--tinta-fija);
font: 400 1rem/1.6 var(--texto);
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
a { color: inherit; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 2px; }
.salto {
position: absolute; left: var(--margen); top: -4rem; z-index: 10;
background: var(--tinta-fija); color: var(--crema); padding: .6rem 1rem; text-decoration: none;
}
.salto:focus { top: 1rem; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.etiqueta {
font: 600 .72rem/1.2 var(--texto);
letter-spacing: .16em;
text-transform: uppercase;
}
/* ---------- 4. Héroe ---------- */
.heroe {
position: relative;
isolation: isolate;
min-height: 100svh;
display: grid;
grid-template-rows: auto 1fr auto;
gap: 2rem;
padding: var(--margen);
color: var(--tinta);
transition: --m0 1.4s var(--salida), --m1 1.4s var(--salida), --m2 1.4s var(--salida),
--m3 1.4s var(--salida), --m4 1.4s var(--salida), --m5 1.4s var(--salida),
--tinta 1.4s var(--salida);
}
.heroe:has(#nota-corazon:checked) { --m0: #f7e2dc; --m1: #f09a88; --m2: #f9cbbd; --m3: #fff7ee; --m4: #de7f93; --m5: #f3c178; --tinta: #2a1518; }
.heroe:has(#nota-fondo:checked) { --m0: #1a1320; --m1: #5a2f24; --m2: #8a5127; --m3: #2b2140; --m4: #6e3b25; --m5: #34463f; --tinta: #f6eee2; }
.heroe > .malla { position: absolute; inset: 0; z-index: -1; }
.cabecera { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; }
.marca { display: flex; flex-direction: column; text-decoration: none; line-height: 1; }
.marca b { font: italic 500 1.65rem/1 var(--display); letter-spacing: -.01em; }
.marca span { margin-top: .4rem; font-size: .66rem; }
.cabecera nav ul { display: flex; align-items: center; gap: clamp(1rem, 2.4vw, 2.25rem); margin: 0; padding: 0; list-style: none; }
.cabecera nav a { font-size: .92rem; font-weight: 500; text-decoration: none; background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat; transition: background-size .5s var(--salida); padding-bottom: 2px; }
.cabecera nav a:hover { background-size: 100% 1px; }
.cabecera nav a.boton-linea { white-space: nowrap; border: 1px solid currentColor; border-radius: 999px; padding: .55rem 1.1rem; background: none; transition: background-color .4s var(--salida), color .4s var(--salida); }
.cabecera nav a.boton-linea:hover { background: var(--tinta); color: var(--m0); }
.centro {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(16rem, 21rem);
align-items: end;
gap: clamp(2rem, 5vw, 5rem);
}
.titular {
margin: 0;
font: 500 clamp(4.4rem, 12.4vw, 11.75rem)/.84 var(--display);
letter-spacing: -.04em;
font-optical-sizing: auto;
}
.titular em { display: block; font-style: italic; font-weight: 400; padding-left: .42em; }
.titular sup {
font: 600 .72rem/1 var(--texto); letter-spacing: .16em; text-transform: uppercase;
vertical-align: top; position: relative; top: 2.6em; margin-left: .7em; font-style: normal; white-space: nowrap;
}
.entradilla { max-width: 34ch; margin: clamp(1.5rem, 3vw, 2.5rem) 0 0; font-size: clamp(1.02rem, 1.3vw, 1.15rem); line-height: 1.55; }
.acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.75rem; margin-top: 1.75rem; }
.boton {
display: inline-flex; align-items: center; gap: .7rem;
padding: 1rem 1.5rem; border-radius: 999px;
background: var(--tinta); color: var(--m0);
font-weight: 600; text-decoration: none;
transition: transform .5s var(--salida);
}
.boton:hover { transform: translateY(-2px); }
.boton svg { width: 1rem; height: 1rem; transition: transform .5s var(--salida); }
.boton:hover svg { transform: translateX(3px); }
.precio { font-size: .92rem; }
.precio strong { font: 500 1.35rem/1 var(--display); margin-right: .35rem; }
.notas { border: 0; margin: 0; padding: 0; min-width: 0; }
.notas legend { padding: 0; margin-bottom: 1rem; }
.notas-lista { display: grid; gap: .5rem; }
.nota {
position: relative;
display: grid;
grid-template-columns: 2.2rem 1fr;
align-items: baseline;
padding: .95rem 1.1rem;
border: 1px solid color-mix(in srgb, var(--tinta) 30%, transparent);
border-radius: 14px;
cursor: pointer;
transition: background-color .6s var(--salida), color .6s var(--salida), border-color .6s var(--salida);
}
.nota:hover { border-color: var(--tinta); }
.nota input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.nota .num { font: italic 400 1rem/1 var(--display); opacity: .8; }
.nota .nombre { font: 500 1.35rem/1.1 var(--display); }
.nota .detalle { grid-column: 2; font-size: .84rem; opacity: .85; margin-top: .2rem; }
.nota:has(input:checked) { background: var(--tinta); color: var(--m0); border-color: var(--tinta); }
.nota:has(input:focus-visible) { outline: 2px solid var(--tinta); outline-offset: 3px; }
.pie-heroe { display: flex; justify-content: space-between; align-items: end; gap: 1rem; font-size: .88rem; }
.desliza { display: inline-flex; align-items: center; gap: .75rem; text-decoration: none; }
.desliza i { display: block; width: 1px; height: 2.6rem; background: currentColor; transform-origin: top; animation: goteo 2.4s var(--salida) infinite; }
@keyframes goteo { 0% { transform: scaleY(0); } 55% { transform: scaleY(1); transform-origin: top; } 56% { transform-origin: bottom; } 100% { transform: scaleY(0); transform-origin: bottom; } }
/* ---------- 5. Pirámide ---------- */
.piramide { padding: clamp(5rem, 11vw, 9rem) var(--margen); }
.piramide-cabeza { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 26rem); gap: 1.5rem 4rem; align-items: end; margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }
.piramide h2, .taller h2 { margin: .9rem 0 0; font: 400 clamp(2.6rem, 6.4vw, 5.6rem)/.95 var(--display); letter-spacing: -.035em; }
.piramide h2 em, .taller h2 em { font-style: italic; }
.piramide-cabeza p { margin: 0; color: #4a3d30; }
.tarjetas { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1rem, 2.2vw, 2rem); margin: 0; padding: 0; list-style: none; }
.tarjeta .malla { aspect-ratio: 4 / 5; border-radius: 22px; color: var(--tinta); padding: 1.2rem 1.3rem; display: flex; flex-direction: column; justify-content: space-between; }
.tarjeta .malla > * { position: relative; z-index: 1; }
.tarjeta .malla .grande { font: italic 400 clamp(4rem, 8vw, 7rem)/.8 var(--display); letter-spacing: -.04em; }
.tarjeta:nth-child(2) .malla { animation-delay: -4s, -9s, -2s, -12s, -7s; }
.tarjeta:nth-child(3) .malla { animation-delay: -8s, -3s, -6s, -5s, -15s; }
.tarjeta h3 { margin: 1.3rem 0 .3rem; font: 500 1.9rem/1.1 var(--display); letter-spacing: -.02em; }
.tarjeta p { margin: 0; color: #4a3d30; max-width: 32ch; }
.tarjeta .dura { display: block; margin-top: .9rem; color: #5b4a3a; }
/* ---------- 6. Taller ---------- */
.taller { background: var(--tinta-fija); color: var(--crema); padding: clamp(5rem, 10vw, 8rem) var(--margen) 2rem; }
.taller-rejilla { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 3rem clamp(3rem, 8vw, 8rem); align-items: start; }
.taller .etiqueta { color: #d9c9b2; }
.sello { width: clamp(7rem, 12vw, 9.5rem); aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center; margin-top: 2.5rem; font: italic 400 1.6rem/1 var(--display); color: var(--tinta); }
.sello span { position: relative; z-index: 1; }
.datos { margin: 0; display: grid; gap: 0; }
.datos div { display: grid; grid-template-columns: 7.5rem 1fr; gap: 1rem; padding: 1.1rem 0; border-top: 1px solid rgba(246, 238, 226, .18); }
.datos div:last-child { border-bottom: 1px solid rgba(246, 238, 226, .18); }
.datos dt { color: #d9c9b2; }
.datos dd { margin: 0; }
.datos a { text-decoration-thickness: 1px; text-underline-offset: 3px; }
.oferta { margin-top: 2rem; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: .5rem 1.5rem; }
.oferta strong { font: 500 2.2rem/1 var(--display); }
.oferta small { color: #d9c9b2; font: 400 .88rem/1.4 var(--texto); }
.creditos { margin-top: clamp(4rem, 8vw, 6rem); padding-top: 1.5rem; border-top: 1px solid rgba(246, 238, 226, .18); display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem 2rem; font-size: .82rem; color: #d9c9b2; }
/* ---------- 7. Adaptación ---------- */
@media (max-width: 960px) {
.centro { grid-template-columns: 1fr; align-items: start; }
.notas-lista { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.nota { grid-template-columns: 1fr; padding: .8rem .9rem; }
.nota .detalle { grid-column: 1; }
.piramide-cabeza, .taller-rejilla { grid-template-columns: 1fr; }
.tarjetas { grid-template-columns: 1fr; max-width: 34rem; }
.tarjeta .malla { aspect-ratio: 16 / 11; }
}
@media (max-width: 640px) {
.cabecera nav li:not(:last-child) { display: none; }
.marca span { font-size: .6rem; letter-spacing: .1em; white-space: nowrap; }
.cabecera nav a.boton-linea { padding: .5rem .95rem; font-size: .86rem; }
.centro { align-content: end; }
.nota { padding: .7rem .75rem; border-radius: 12px; }
.nota .num { display: none; }
.nota .nombre { font-size: 1.15rem; }
.nota .detalle { display: none; }
.pie-heroe .edicion b { display: none; }
.datos div { grid-template-columns: 1fr; gap: .15rem; }
}
/* ---------- 8. Movimiento reducido ---------- */
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.malla, .desliza i { animation: none; }
.heroe, .nota, .boton, .boton svg { transition: none; }
}
```
Detalles que no hay que perder:
- `@property` de colores con `inherits: true` (el héroe cambia la paleta y la malla hija la hereda en cada fotograma de la transición); los de posición con `inherits: false`.
- El orden de las capas del `background` importa: la primera se pinta encima. La mancha 3 (`--m3`, la más clara) es la más pequeña (40% 48%) y la 4 la más grande (58% 66%).
- Cada `radial-gradient` va de su color a `transparent` en 68–74 %; así no hay bordes y las manchas se funden entre sí.
- El grano: `feTurbulence` `fractalNoise`, `baseFrequency .85`, `numOctaves 3`, `stitchTiles stitch`, desaturado con `feColorMatrix type='saturate' values='0'`, en tesela de 240 px, `mix-blend-mode: overlay` y `opacity: .5`, sobre `::after` con `pointer-events: none`.
- Las reglas `.heroe:has(#nota-…:checked)` incluyen un id, así que ganan en especificidad a `.p-salida` sin necesidad de `!important`.
- El radio es invisible (`opacity: 0`) pero ocupa toda la opción y sigue siendo enfocable; el foco se dibuja en la etiqueta con `:has(input:focus-visible)`.
## Interacción
- **Puntero / toque**: pulsar cualquiera de las tres opciones de «Cambia la nota» cambia la paleta del héroe con un fundido de 1,4 s; el texto, los botones y los bordes cambian de color a la vez (todo usa `--tinta` y `--m0`). En Fondo el botón pasa a crema con texto oscuro y la opción marcada se rellena en crema.
- **Teclado**: Tab llega al grupo; las flechas cambian de opción (comportamiento nativo de los radios) y la paleta cambia en vivo. Foco visible de 2 px en color tinta con separación de 3 px.
- **Hover**: subrayado que crece en la navegación, píldora «Pedir muestra» que se rellena, botón que sube 2 px con la flecha avanzando 3 px, opción de nota con el borde a tinta plena.
- **Scroll**: nativo con `scroll-behavior: smooth` para los enlaces internos. No hay efectos ligados al scroll.
- No hay ningún efecto que dependa del puntero, así que en táctil funciona igual.
## Adaptación a móvil y tablet
- **> 960 px**: centro del héroe en dos columnas (`minmax(0,1fr)` y `minmax(16rem,21rem)`), notas apiladas en vertical con número, nombre y detalle; pirámide en tres columnas; taller en dos columnas.
- **≤ 960 px**: el centro pasa a una columna (titular, entradilla, acciones y debajo las notas). Las notas se ponen en fila de tres columnas iguales. Cabecera de la pirámide y taller a una columna. Las tarjetas se apilan (máx. 34rem de ancho) y la malla pasa a proporción 16/11.
- **≤ 640 px**: la navegación deja solo «Pedir muestra» (más compacta: `.5rem .95rem`, `.86rem`). La etiqueta de la marca baja a `.6rem` con tracking `.1em` y sin saltos de línea. En las notas se ocultan el número y el detalle; el nombre baja a 1,15rem. Se oculta «Edición de primavera ·». En «El taller», cada dato pone la etiqueta encima del valor.
- El titular nunca baja de 4,4rem y no provoca scroll horizontal ni a 360 px. `body` lleva `overflow-x: hidden` como red de seguridad, pero nada debe desbordar.
- Se usa `100svh`, nunca `100vh`.
## Accesibilidad y movimiento reducido
- HTML semántico: `header` (héroe), `nav` con `aria-label="Principal"`, `main`, `section` con `aria-labelledby`, `ol` para las tarjetas, `dl` para los datos, `footer`.
- Todas las mallas y el sello llevan `aria-hidden="true"`; los números y tiempos que contienen se repiten como texto real debajo (H3 y etiqueta de duración).
- Selector de paleta nativo: `fieldset` + `legend` + tres `input type="radio"` dentro de su `label`. Funciona con teclado y lector de pantalla sin ARIA extra.
- Contraste AA: con la paleta Salida el color más oscuro de la malla (`#e5704a`) contra la tinta da unos 5,5:1; en Corazón el peor caso (`#de7f93`) supera 5:1; en Fondo el color más claro (`#8a5127`) contra la crema da unos 5,5:1. Si cambias colores, mantén esas relaciones.
- Enlace «Saltar al contenido» visible al recibir foco.
- `prefers-reduced-motion: reduce`: la malla y la línea de «Desliza» se quedan quietas (`animation: none`) en la composición inicial, que es equilibrada; las transiciones de paleta y de botones desaparecen (cambio instantáneo) y el scroll suave se desactiva.
## Rendimiento
- Sin JavaScript, sin WebGL, sin canvas: no hay bucles que parar ni DPR que limitar. El navegador repinta la malla en cada fotograma de animación; son cinco degradados radiales, barato incluso en móvil.
- Los navegadores no pintan lo que queda fuera de pantalla, así que las tarjetas no cuestan mientras no se ven.
- Sin soporte de `@property` (navegadores muy antiguos) la malla se ve igual, pero quieta, y el cambio de paleta es instantáneo: es el fallback natural, no hace falta más.
- Peso objetivo: unos 20 KB de HTML en total, de los que el efecto son unos 2 KB.
## Personalización
- **Colores**: la paleta de inicio está en dos sitios que deben coincidir: los `initial-value` de las `@property` y la regla `.p-salida`. Las otras dos paletas están en `.p-corazon` / `.p-fondo` y repetidas en las dos reglas `.heroe:has(#nota-…:checked)`. Para una malla más viva sube la saturación de `--m1`, `--m2` y `--m4`; para una más serena, acerca los cinco colores a `--m0`.
- **Velocidad**: multiplica las cinco duraciones (13, 17, 11, 19, 23 s) por el mismo factor. Mantén números distintos y sin divisores comunes para que el conjunto no se repita.
- **Recorrido**: cambia los porcentajes de los `@keyframes`; conviene que cada mancha se quede en su cuadrante para que siempre haya contraste de zonas.
- **Grano**: más o menos intenso con `opacity` del `::after` (0,3–0,6) o más fino subiendo `baseFrequency` a 1.
- **Textos y marca**: Maison Aurelle, Valmora, el titular (Agua de / neroli), 68 €, Avenue Bellevue 42, 10003 Valmora, +00 000 000 000 y hola@maisonaurelle.com. En el enlace `tel:` quita los espacios del teléfono si tu herramienta no lo hace.
- **Reutilizar la malla**: la clase `.malla` sirve para cualquier bloque (tarjeta, sello, banda); basta con darle tamaño y una clase de paleta.
## Comprobación final
1. El archivo no contiene ninguna etiqueta `<script>`.
2. Al cargar, las cinco manchas se mueven lentamente y de forma continua en el héroe y en las tres tarjetas, sin saltos al final de cada ciclo.
3. Hay grano visible sobre todas las mallas (héroe, tarjetas y sello).
4. Pulsar «Corazón» funde el héroe a rosas en unos 1,4 s; «Fondo» lo lleva a marrones y noche con el texto en crema; «Salida» vuelve al naranja. No hay saltos bruscos de color.
5. Con el teclado se llega al grupo de notas, las flechas cambian la paleta y el foco se ve.
6. El titular «Agua de *neroli*» usa Bodoni Moda con la segunda línea en cursiva desplazada y el superíndice «N.º 7».
7. Todos los textos están en español y coinciden con los de este documento, precios con «IVA incl.».
8. A 390 px las notas se ven en fila de tres, la navegación solo muestra «Pedir muestra» y no hay scroll horizontal (tampoco a 360 px).
9. A 960 px o menos las tarjetas se apilan y la malla de cada una pasa a 16/11.
10. Con `prefers-reduced-motion: reduce` nada se mueve y todo sigue legible.
11. El texto cumple contraste AA sobre la malla en las tres paletas.
12. No hay errores en la consola ni peticiones fallidas (solo se cargan las fuentes de Google).Prueba en frío
Pegamos el prompt en Claude Sonnet 5.5, sin ayuda ni contexto, y comparamos el resultado con la demo. Prueba hecha el 30-09-2026.

Calco del original: mismo HTML y CSS salvo espacios, así que la malla, el grano, el fundido de paleta de 1,4 s y la versión móvil son idénticos. Solo cambia la fase de la animación en el momento de la captura.

El núcleo sale exacto: malla de cinco manchas, grano, cambio de paleta con :has() y tarjetas desincronizadas. Cambia el acabado editorial: la navegación va en mayúsculas, el «N.º 7» sube a la primera línea, los nombres de nota van en cursiva, el precio sale más grande y la cabecera de la pirámide y los datos del taller se maquetan de otra forma.
Solo publicamos lo que hemos probado. Otras herramientas (ChatGPT, Gemini, Lovable…) pueden dar resultados distintos.
Paso a paso
Personaliza
Copia el Completo o el Lite
Pega e itera
Publica
Licencia en claro
Todas las piezas incluyen licencia de uso comercial. Usa el resultado tal cual en tus productos, encargos freelance o webs de clientes, sin atribución.
Puedes
No puedes
Es la misma licencia para lo gratis y lo Pro. La tienes entera en licencia de uso.
Preguntas frecuentes
Versión 1.0 · publicada el 30-09-2026