radionicapp / css /componentes /carta.css
Javier Villarroel
feat: la aurora sustituye a la nebulosa en el cielo
f747c64
Raw History Blame Contribute Delete
13.1 kB
/* Carta β€” la herramienta. Vive sobre el cielo, no a pantalla completa. */
.taller {
position: relative;
z-index: 1;
min-height: 100dvh;
display: flex;
align-items: center;
justify-content: center;
padding: var(--e-7);
}
.carta {
position: relative;
width: min(var(--m-carta-ancho), 100%);
height: min(var(--m-carta-alto), calc(100dvh - var(--e-11)));
display: grid;
grid-template-columns: minmax(0, 1fr) var(--m-panel-ancho);
border-radius: var(--r-xl);
overflow: hidden;
/* La carta es el vidrio: el cielo se ve a travΓ©s suyo (por eso el
desenfoque), y cada mitad pinta encima lo suyo (el escenario, su propio
velo oscuro; el panel, nada, para que este vidrio se le note debajo). */
background: var(--vidrio-fondo);
backdrop-filter: var(--vidrio-desenfoque);
-webkit-backdrop-filter: var(--vidrio-desenfoque);
color: var(--texto-principal);
box-shadow: var(--vidrio-sombra), var(--sombra-carta), 0 0 0 1px var(--borde-carta);
}
/* El borde: un degradado de 1px recortado con mask, no un `border` plano.
Y el grano: una textura fija, que pone js/cielo.js en --grano al arrancar. */
.carta::before,
.carta::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
}
.carta::before {
padding: 1px;
background: var(--vidrio-borde-degradado);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); /* token-libre: mΓ‘scara, no es color de diseΓ±o */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
.carta::after {
background-image: var(--grano);
background-size: var(--vidrio-grano-tamano);
opacity: var(--vidrio-grano-opacidad);
mix-blend-mode: overlay;
}
/* ── Escenario: la imagen, entera, nunca recortada a sangre ──────────── */
.escenario {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: var(--e-11);
background: var(--superficie-escenario);
overflow: hidden;
}
.escenario__lienzo {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
/* ── La pila: antes debajo, despuΓ©s encima ────────────────────────────
Las dos capas son la misma imagen pasada por el proceso. La de despuΓ©s se
descubre de arriba abajo con una lΓ­nea, como cuando arrastras el separador
de un antes/despuΓ©s. Cuando un paso del proceso cambie el archivo, la capa
de despuΓ©s apunta a ese resultado y esto sigue funcionando igual. */
.pila {
position: relative;
display: inline-block;
max-width: 100%;
max-height: 100%;
line-height: 0;
border-radius: var(--r-s);
overflow: hidden;
box-shadow: var(--sombra-imagen);
}
.pila[data-giro] { transform: rotate(var(--giro-imagen)); }
.escenario__imagen {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
}
.pila__despues {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
clip-path: inset(0 0 100% 0);
}
/* El frente: una banda de luz difuminada que recorre la imagen de arriba abajo.
Por su centro va pasando el revelado β€”de ahΓ­ para arriba ya estΓ‘ la imagen
que ha salido del procesoβ€”, pero sin ninguna lΓ­nea que lo seΓ±ale. */
.pila__frente {
position: absolute;
left: 0;
right: 0;
top: 0;
height: var(--m-difuminado-alto);
max-height: 60%;
transform: translateY(-50%);
background: var(--revelado-difuminado);
filter: blur(var(--revelado-suavizado));
opacity: 0;
pointer-events: none;
}
/* Mientras se aplica, el frente va descubriendo la imagen que sale del proceso.
La de partida no se toca: nada de apagarla ni desaturarla, que marcaba un
borde duro al pasar y se leΓ­a como un blanco y negro. */
.app[data-fase="aplicando"] .pila__despues {
animation: revela var(--t-aplicando) var(--curva-calma) forwards;
}
.app[data-fase="aplicando"] .pila__frente {
animation: baja var(--t-aplicando) var(--curva-calma) forwards;
}
.app[data-fase="hecho"] .pila__despues { clip-path: inset(0 0 0 0); }
/* El velo de la magia, sobre la imagen (js/aurora.js pone la opacidad, con
la misma campana que la distorsiΓ³n): tres manchas radiales en los tres
colores de la aurora, `screen` para solo aclarar. En reposo no se ve. */
.pila__velo-magia {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0;
background:
radial-gradient(45% 45% at 30% 35%, rgb(var(--c-teal-rgb) / 0.5) 0%, rgb(var(--c-teal-rgb) / 0) 70%),
radial-gradient(45% 45% at 70% 30%, rgb(var(--c-violeta-rgb) / 0.45) 0%, rgb(var(--c-violeta-rgb) / 0) 70%),
radial-gradient(50% 50% at 55% 75%, rgb(var(--c-rosa-rgb) / 0.4) 0%, rgb(var(--c-rosa-rgb) / 0) 70%);
filter: blur(var(--aurora-velo-difuminado));
mix-blend-mode: screen;
pointer-events: none;
}
.pila[data-comparando="si"] .pila__velo-magia { display: none; }
/* Comparar: antes y despuΓ©s lado a lado, en vez de revelado superpuesto. */
.pila[data-comparando="si"] {
display: flex;
align-items: center;
gap: var(--e-4);
}
.pila[data-comparando="si"] .pila__despues {
position: relative;
inset: auto;
width: auto;
height: auto;
clip-path: none;
}
.pila[data-comparando="si"] .pila__frente { display: none; }
.pila[data-comparando="si"] .escenario__imagen {
max-width: calc(50% - var(--e-2));
}
@keyframes revela {
from { clip-path: inset(0 0 100% 0); }
to { clip-path: inset(0 0 0 0); }
}
@keyframes baja {
0% { top: 0; opacity: 0; }
6% { opacity: 1; }
94% { opacity: 1; }
100% { top: 100%; opacity: 0; }
}
.escenario__hueco {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--e-6);
width: 78%;
height: 76%;
border: 1px dashed var(--borde-hueco);
border-radius: var(--r-l);
font-size: var(--f-m);
color: var(--texto-escenario);
text-align: center;
padding: var(--e-7);
}
.escenario__sello {
position: absolute;
left: var(--e-10);
bottom: var(--e-8);
font-size: var(--f-sm);
color: var(--texto-escenario-tenue);
}
/* Las acciones pertenecen a la imagen: se descubren ahΓ­, no en un paso
repetido del formulario. */
.herramientas-imagen {
position: absolute;
bottom: var(--e-6);
left: 50%;
z-index: 2;
display: flex;
gap: var(--e-2);
transform: translateX(-50%);
}
.icono {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--m-icono);
height: var(--m-icono);
padding: var(--e-0);
border: 1px solid var(--borde-menu);
border-radius: var(--r-circulo);
background: var(--superficie-herramientas);
color: var(--texto-herramientas);
font-size: var(--f-md);
line-height: 1;
}
/* Los iconos de la imagen son vidrio, igual que la carta. */
.icono--herramienta {
position: relative;
backdrop-filter: var(--vidrio-desenfoque);
-webkit-backdrop-filter: var(--vidrio-desenfoque);
box-shadow: var(--vidrio-sombra), var(--sombra-imagen);
}
.icono--herramienta::before,
.icono--herramienta::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
}
.icono--herramienta::before {
padding: 1px;
background: var(--vidrio-borde-degradado);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); /* token-libre: mΓ‘scara, no es color de diseΓ±o */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
.icono--herramienta::after {
background-image: var(--grano);
background-size: var(--vidrio-grano-tamano);
opacity: var(--vidrio-grano-opacidad);
mix-blend-mode: overlay;
}
.icono--herramienta svg {
width: var(--e-7);
height: var(--e-7);
fill: none;
stroke: currentColor;
stroke-width: var(--m-trazo-simbolo);
stroke-linecap: round;
stroke-linejoin: round;
}
.icono--herramienta:disabled { opacity: 0.48; cursor: default; }
.menu-imagen {
position: absolute;
bottom: calc(100% + var(--e-3));
left: var(--e-0);
width: var(--m-menu-imagen);
padding: var(--e-4);
border: 1px solid var(--borde-sutil);
border-radius: var(--r-m);
background: var(--superficie-menu);
backdrop-filter: var(--vidrio-desenfoque);
-webkit-backdrop-filter: var(--vidrio-desenfoque);
box-shadow: var(--vidrio-sombra), var(--sombra-imagen);
color: var(--texto-principal);
}
.menu-imagen::before,
.menu-imagen::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
}
.menu-imagen::before {
padding: 1px;
background: var(--vidrio-borde-degradado);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); /* token-libre: mΓ‘scara, no es color de diseΓ±o */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
.menu-imagen::after {
background-image: var(--grano);
background-size: var(--vidrio-grano-tamano);
opacity: var(--vidrio-grano-opacidad);
mix-blend-mode: overlay;
}
.menu-imagen__accion,
.menu-imagen__titulo {
display: block;
width: 100%;
padding: var(--e-3) var(--e-2);
background: none;
border: 0;
color: var(--texto-secundario);
font-size: var(--f-sm);
text-align: left;
}
.menu-imagen__accion:hover { color: var(--texto-principal); }
.menu-imagen__titulo { color: var(--texto-tenue); }
.menu-imagen .miniaturas { padding: 0 var(--e-2) var(--e-2); }
/* El enlace del hueco vive sobre el cielo, no sobre la carta. */
.escenario__hueco .enlace {
color: var(--texto-escenario);
border-bottom-color: var(--borde-hueco);
}
.escenario__hueco .enlace:hover {
color: var(--texto-escenario-fuerte);
border-bottom-color: var(--borde-hueco-fuerte);
}
/* ── El momento de aplicar ───────────────────────────────────────────── */
.anillo {
position: absolute;
width: var(--m-anillo);
height: var(--m-anillo);
max-width: 90%;
max-height: 90%;
border: 1px solid var(--aplicando-anillo);
border-radius: var(--r-circulo);
pointer-events: none;
animation: respira var(--t-respiracion) var(--curva-calma) infinite;
}
.anillo--tarde { animation-delay: calc(var(--t-respiracion) / 2); }
@keyframes respira {
0% { transform: scale(0.84); opacity: 0; }
40% { opacity: 0.75; }
100% { transform: scale(1.26); opacity: 0; }
}
/* ── Panel: los pasos ────────────────────────────────────────────────── */
.panel {
/* Referencia de tamaΓ±o para las cuatro acciones del proceso. */
container-type: inline-size;
display: flex;
flex-direction: column;
padding: var(--e-8) var(--e-6) var(--e-6);
/* Sin fondo propio: el vidrio de .carta se le nota debajo. Solo la lΓ­nea
que lo separa del escenario es suya. */
background: none;
border-left: 1px solid var(--borde-panel);
overflow-y: auto;
}
.panel__paso + .panel__paso { margin-top: var(--e-8); }
.panel__eleccion {
display: flex;
align-items: center;
gap: var(--e-5);
flex-wrap: wrap;
}
.panel__cierre {
display: flex;
flex-direction: column;
gap: var(--e-4);
margin-top: auto;
padding-top: var(--e-8);
}
.panel__nota {
font-size: var(--f-s);
color: var(--texto-tenue);
text-align: center;
margin: 0;
min-height: calc(var(--f-s) * var(--f-alto-normal));
}
.panel__grupo {
display: flex;
flex-direction: column;
gap: var(--e-3);
}
/* ── Estrecho: una sola columna, imagen arriba ───────────────────────── */
@media (max-width: 900px) {
.taller {
padding: var(--m-margen-ventana-movil);
/* Centrada: el margen de arriba y el de abajo son el mismo. `safe` evita
que se corte por arriba si la carta no cupiera. */
align-items: safe center;
}
.carta {
grid-template-columns: minmax(0, 1fr);
/* El alto de la zona de la imagen lo fija la rejilla, no el contenido:
asΓ­ la carta mide lo mismo con imagen y sin ella. */
grid-template-rows: var(--m-escenario-movil) auto;
height: auto;
}
.escenario {
padding: var(--e-6);
min-height: var(--m-escenario-estrecho);
}
.escenario__sello { left: var(--e-7); bottom: var(--e-5); }
.herramientas-imagen { bottom: var(--e-5); }
.pila[data-comparando="si"] {
flex-direction: column;
}
.pila[data-comparando="si"] .escenario__imagen {
max-width: 100%;
max-height: calc(50% - var(--e-2));
}
.panel {
border-left: 0;
border-top: 1px solid var(--borde-panel);
padding: var(--e-6);
overflow-y: visible;
}
.panel__paso + .panel__paso { margin-top: var(--e-7); }
.panel__cierre { padding-top: var(--e-6); gap: var(--e-3); }
}
/* Pantallas de mΓ³vil pequeΓ±as: todo lo necesario para aplicar cabe sin scroll. */
@media (max-width: 640px) {
.escenario { min-height: var(--m-escenario-movil); padding: var(--e-5); }
/* El primer vistazo pertenece a la imagen; los controles continΓΊan debajo. */
.panel { padding: var(--e-5); }
.panel__paso + .panel__paso { margin-top: var(--e-6); }
.panel__cierre { padding-top: var(--e-5); }
}