You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
861 lines
25 KiB
861 lines
25 KiB
@import './fuentes.css';
|
|
/*
|
|
* ---------------------------------------------------------------------------
|
|
* DIRECCIÓN VISUAL
|
|
* ---------------------------------------------------------------------------
|
|
* Los colores de marca: azul marino oscuro aterciopelado y dorado.
|
|
*
|
|
* El marino lleva croma de verdad (0,04) en lugar de ser un gris azulado: eso
|
|
* es lo que le da el aspecto de terciopelo en vez de el de pizarra. Todos los
|
|
* fondos comparten el mismo tono, así que la profundidad la marca la claridad,
|
|
* nunca un cambio de color.
|
|
*
|
|
* El dorado es el único acento y lo llevan las cosas accionables; nada más lo
|
|
* usa, que es lo que hace que se note.
|
|
*
|
|
* Se compromete con un solo modo, sin variante clara: la portada es un fondo a
|
|
* sangre con texto encima y esa composición no sobrevive a un fondo blanco sin
|
|
* rehacerla entera. `color-scheme: dark` avisa al navegador para que sus
|
|
* controles vayan a juego.
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
|
|
:root {
|
|
color-scheme: dark;
|
|
|
|
/* Marino, del más hondo al más cercano. Mismo tono, distinta claridad. */
|
|
--c-bg: oklch(0.16 0.042 264);
|
|
--c-bg-raised: oklch(0.21 0.046 264);
|
|
--c-bg-sunken: oklch(0.26 0.05 264);
|
|
--c-border: oklch(0.33 0.045 264);
|
|
|
|
/* Blancos apenas teñidos: por encima de 0,02 de croma dejarían de leerse
|
|
como blancos y competirían con el dorado. */
|
|
--c-text: oklch(0.96 0.012 255);
|
|
--c-text-muted: oklch(0.74 0.022 258);
|
|
|
|
/*
|
|
* El oro. El plano de antes tiraba a amarillo; este baja de claridad y sube
|
|
* de croma, que es lo que separa un metal de un color de rotulador.
|
|
*/
|
|
--c-accent: oklch(0.8 0.145 84);
|
|
--c-accent-text: oklch(0.16 0.042 264);
|
|
/*
|
|
* El dorado como superficie va aparte del dorado como texto, porque no
|
|
* pueden ser el mismo valor: relleno necesita ser claro para que encima se
|
|
* lea el marino, y escrito necesita ser oscuro para leerse sobre el fondo.
|
|
* En el tema oscuro coinciden; en el claro no, y por eso existe la
|
|
* distinción.
|
|
*/
|
|
--c-accent-superficie: oklch(0.8 0.145 84);
|
|
/* Los dos extremos del reflejo: la luz que lo cruza y la sombra del canto. */
|
|
--c-accent-brillo: oklch(0.94 0.095 96);
|
|
--c-accent-sombra: oklch(0.63 0.13 72);
|
|
|
|
/*
|
|
* El verdemar: el tercer color de la paleta, para datos.
|
|
*
|
|
* El mapa necesitaba dos intensidades de algo que no fuera el dorado, y
|
|
* mezclarlo con el fondo marino daba barro —literalmente un marrón sucio—.
|
|
* Este es de la misma familia que el marino, un paso hacia el verde, así que
|
|
* conviven sin pelearse; y deja el dorado para lo que se pulsa y lo que se
|
|
* elige, que es su trabajo en el resto del sitio.
|
|
*/
|
|
--c-dato: oklch(0.74 0.09 198);
|
|
/* El mismo tono, un paso por debajo: «también se canta aquí», no otro dato. */
|
|
--c-dato-tenue: oklch(0.66 0.085 198);
|
|
--c-dato-vacio: oklch(0.29 0.03 255);
|
|
|
|
--c-danger: oklch(0.72 0.16 22);
|
|
--c-focus: oklch(0.84 0.12 88);
|
|
|
|
/*
|
|
* Dos familias: una serif con carácter para los títulos y para la letra de
|
|
* las canciones —que es texto para leer despacio— y una sans de rejilla
|
|
* para interfaz, datos y navegación.
|
|
*/
|
|
--font-display: 'Newsreader', 'Iowan Old Style', Georgia, serif;
|
|
--font-body: 'Archivo', ui-sans-serif, system-ui, sans-serif;
|
|
--font-versos: var(--font-display);
|
|
--font-mono: ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Consolas, monospace;
|
|
|
|
/* Escala amplia: el salto entre texto y titular es parte del carácter. */
|
|
--fs-xs: 0.75rem;
|
|
--fs-sm: 0.875rem;
|
|
--fs-base: 1rem;
|
|
--fs-lg: 1.1875rem;
|
|
--fs-xl: 1.5rem;
|
|
--fs-2xl: 2.125rem;
|
|
--fs-3xl: 3rem;
|
|
--fs-4xl: clamp(3.25rem, 9vw, 6rem);
|
|
|
|
--sp-1: 0.25rem;
|
|
--sp-2: 0.5rem;
|
|
--sp-3: 0.75rem;
|
|
--sp-4: 1rem;
|
|
--sp-5: 1.5rem;
|
|
--sp-6: 2rem;
|
|
--sp-7: 3rem;
|
|
--sp-8: 5rem;
|
|
|
|
/*
|
|
* El oro de una superficie no es un color plano: un metal refleja, y lo que
|
|
* lo hace parecer metal es la banda de luz que lo cruza. Cinco paradas —de
|
|
* la sombra del canto al brillo y otra vez a la sombra— bastan para
|
|
* sugerirlo sin que parezca un tubo de cromo.
|
|
*
|
|
* El fondo se pinta más alto que el elemento a propósito: así, al acercar el
|
|
* puntero, se desplaza y la luz recorre la pieza en vez de limitarse a
|
|
* aclararla. Es la diferencia entre algo que se ilumina y algo que gira.
|
|
*/
|
|
--oro: linear-gradient(
|
|
166deg,
|
|
var(--c-accent-sombra) 0%,
|
|
var(--c-accent-superficie) 24%,
|
|
var(--c-accent-brillo) 46%,
|
|
var(--c-accent-superficie) 64%,
|
|
var(--c-accent-sombra) 100%
|
|
);
|
|
|
|
/*
|
|
* El mismo metal, pero para recortarlo sobre unas letras.
|
|
*
|
|
* El dorado hace dos trabajos y no puede ser el mismo valor en los dos: de
|
|
* relleno tiene que ser claro para que encima se lea el marino, y escrito
|
|
* tiene que ser hondo para leerse sobre el fondo. Sobre marino las cinco
|
|
* paradas de `--oro` valen —la peor da 5,4 de contraste—, así que aquí es
|
|
* literalmente el mismo. En claro no: ahí el brillo se queda en 1,26 y la
|
|
* marca desaparece, y por eso el tema claro lo redefine.
|
|
*/
|
|
--oro-escrito: var(--oro);
|
|
|
|
/*
|
|
* Dos radios y no más, para que nada se vea de otra familia:
|
|
*
|
|
* - `--radius-boton` para lo que se pulsa o se escribe: botones, campos,
|
|
* pastillas.
|
|
* - `--radius-tarjeta` para las superficies: tarjetas, paneles, portadas.
|
|
*
|
|
* Un canto muy redondo tira a aplicación de móvil, y esto es una web de
|
|
* letras: la esquina corta acompaña mejor a una serif.
|
|
*/
|
|
--radius-boton: 6px;
|
|
|
|
/*
|
|
* Los botones. Un solo tamaño y un solo relleno, porque antes convivían tres
|
|
* —el dorado a 16px con relleno 8/16, el de al lado a 14px con 12/24— y dos
|
|
* botones juntos con distinta letra se ven como un descuido.
|
|
*
|
|
* 15px es el mismo cuerpo del menú: lo pulsable se lee igual en todas
|
|
* partes.
|
|
*/
|
|
--boton-texto: 0.9375rem;
|
|
--boton-relleno: var(--sp-3) var(--sp-5);
|
|
/* La versión reducida, para las esquinas de una tarjeta o una fila. */
|
|
--boton-texto-corto: 0.8125rem;
|
|
--boton-relleno-corto: var(--sp-2) var(--sp-3);
|
|
--radius-tarjeta: 8px;
|
|
|
|
/*
|
|
* Curvas del movimiento. `--sal` sale rápido y frena largo, que es como se
|
|
* mueve algo que pesa; `--suave` es para lo que solo cambia de color o de
|
|
* opacidad y no tiene inercia que fingir. Nada usa `ease`, que es la curva
|
|
* por defecto y hace que todo se parezca.
|
|
*/
|
|
--sal: cubic-bezier(0.16, 1, 0.3, 1);
|
|
--suave: cubic-bezier(0.4, 0, 0.2, 1);
|
|
/*
|
|
* El ancho útil: 1184px. Se probó a subirlo a 88rem (1408px) para aprovechar
|
|
* los monitores anchos y salió al revés: la prosa tiene una medida de
|
|
* lectura y no crece con el contenedor, así que lo único que se ensanchó
|
|
* fue el hueco a su derecha. En la página legal se veía a la legua.
|
|
*
|
|
* Si algún día se ensancha, hay que dar antes a cada texto una columna que
|
|
* crezca con él; sin eso, más ancho es más vacío.
|
|
*/
|
|
--container: 74rem;
|
|
|
|
/* Alto de la barra del reproductor: lo usa el padding inferior del layout. */
|
|
--player-height: 88px;
|
|
|
|
/*
|
|
* Altura aproximada de la cabecera, que ahora es pegajosa. No la mide nadie:
|
|
* es una referencia para separar de ella las anclas y las barras laterales
|
|
* que también se quedan fijas. Si cambia el espaciado de la cabecera, este
|
|
* número la sigue.
|
|
*/
|
|
--altura-cabecera: 4.75rem;
|
|
}
|
|
|
|
/*
|
|
* La inversión clara, y SOLO cuando se pide.
|
|
*
|
|
* El marino es el modo por defecto se pida lo que se pida al sistema, y no es
|
|
* un descuido: es la marca. Un sitio cuyo color forma parte de lo que cuenta no
|
|
* puede salir en blanco porque el portátil de quien entra venga configurado
|
|
* así; y al revés que en una herramienta de trabajo, aquí nadie va a pasar ocho
|
|
* horas seguidas leyendo. Antes esto seguía a `prefers-color-scheme` y llevaba
|
|
* a que media parte de las visitas viera una versión que no es la del sitio.
|
|
*
|
|
* El claro sigue entero y a un clic, en el botón de la cabecera, y la elección
|
|
* se recuerda. Lo que se deja de hacer es decidirlo por nadie a partir de una
|
|
* preferencia que se configuró pensando en otra cosa.
|
|
*
|
|
* Es una inversión de verdad, no un fondo blanco con lo mismo encima: el texto
|
|
* pasa a ser el propio marino y los fondos, blancos apenas teñidos de él. Así
|
|
* los dos modos son la misma marca vista de dos maneras.
|
|
*
|
|
* El dorado tiene que bajar de claridad aquí. El de 0,82 se lee bien sobre
|
|
* marino y desaparece sobre blanco, así que este es un dorado más hondo, casi
|
|
* bronce, que mantiene el contraste como texto.
|
|
*/
|
|
:root[data-tema='claro'] {
|
|
color-scheme: light;
|
|
--c-bg: oklch(0.98 0.008 264);
|
|
--c-bg-raised: oklch(0.955 0.011 264);
|
|
--c-bg-sunken: oklch(0.915 0.016 264);
|
|
--c-border: oklch(0.86 0.02 264);
|
|
|
|
--c-text: oklch(0.24 0.055 264);
|
|
--c-text-muted: oklch(0.48 0.038 264);
|
|
|
|
--c-accent: oklch(0.52 0.125 74);
|
|
--c-accent-superficie: oklch(0.76 0.13 82);
|
|
--c-accent-text: oklch(0.24 0.055 264);
|
|
--c-accent-brillo: oklch(0.9 0.1 92);
|
|
--c-accent-sombra: oklch(0.6 0.12 74);
|
|
|
|
/*
|
|
* El oro escrito, sobre papel.
|
|
*
|
|
* Aquí la banda va al revés que en el botón: el punto más claro es el propio
|
|
* `--c-accent` y los extremos se oscurecen. Medido contra este fondo, el
|
|
* acento da 5,29 de contraste y las tres paradas del oro de relleno dan
|
|
* 1,26, 2,05 y 3,79 —las tres por debajo del mínimo—, así que un degradado
|
|
* que subiera del acento dejaría el centro de las letras ilegible.
|
|
*
|
|
* Sigue pareciendo metal porque lo que hace el efecto es la banda que cruza,
|
|
* no que llegue a brillar.
|
|
*/
|
|
--oro-escrito: linear-gradient(
|
|
166deg,
|
|
color-mix(in oklab, var(--c-accent) 68%, black) 0%,
|
|
color-mix(in oklab, var(--c-accent) 84%, black) 24%,
|
|
var(--c-accent) 46%,
|
|
color-mix(in oklab, var(--c-accent) 84%, black) 64%,
|
|
color-mix(in oklab, var(--c-accent) 68%, black) 100%
|
|
);
|
|
|
|
/* En claro se invierten: el dato pintado tiene que ser oscuro sobre papel. */
|
|
--c-dato: oklch(0.5 0.085 200);
|
|
/* El mismo tono, un paso por debajo: «también se canta aquí», no otro dato. */
|
|
--c-dato-tenue: oklch(0.62 0.08 200);
|
|
--c-dato-vacio: oklch(0.93 0.012 255);
|
|
|
|
--c-danger: oklch(0.5 0.17 25);
|
|
--c-focus: oklch(0.5 0.13 264);
|
|
}
|
|
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
-webkit-text-size-adjust: 100%;
|
|
/*
|
|
* Sin esto, un enlace a un ancla dejaría su destino debajo de la cabecera
|
|
* pegajosa. Vale para los saltos con teclado y para el enlace de saltar al
|
|
* contenido, no solo para los `#` escritos a mano.
|
|
*/
|
|
scroll-padding-top: calc(var(--altura-cabecera) + var(--sp-4));
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--c-bg);
|
|
color: var(--c-text);
|
|
font-family: var(--font-body);
|
|
font-size: var(--fs-base);
|
|
line-height: 1.65;
|
|
-webkit-font-smoothing: antialiased;
|
|
text-rendering: optimizeLegibility;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4 {
|
|
font-family: var(--font-display);
|
|
line-height: 1.1;
|
|
margin: 0 0 var(--sp-3);
|
|
font-weight: 400;
|
|
letter-spacing: -0.015em;
|
|
text-wrap: balance;
|
|
}
|
|
|
|
h1 {
|
|
font-size: var(--fs-3xl);
|
|
}
|
|
h2 {
|
|
font-size: var(--fs-2xl);
|
|
}
|
|
h3 {
|
|
font-size: var(--fs-xl);
|
|
}
|
|
|
|
p {
|
|
margin: 0 0 var(--sp-4);
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
a {
|
|
color: inherit;
|
|
text-underline-offset: 0.2em;
|
|
transition: color 0.2s var(--suave);
|
|
}
|
|
|
|
/*
|
|
* Todo enlace responde al puntero. Antes no había ninguna regla global, así que
|
|
* los enlaces sin estilo propio —el del feed, los del pie— no daban ninguna
|
|
* señal de ser pulsables. El dorado es el color de lo accionable en esta web,
|
|
* así que es el que corresponde.
|
|
*
|
|
* Los componentes que ya deciden su propio color al pasar por encima ganan por
|
|
* especificidad: esto es el suelo, no una imposición.
|
|
*/
|
|
a:hover {
|
|
color: var(--c-accent);
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
a {
|
|
transition: none;
|
|
}
|
|
}
|
|
|
|
img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
display: block;
|
|
}
|
|
|
|
ul,
|
|
ol {
|
|
margin: 0 0 var(--sp-4);
|
|
padding-left: var(--sp-5);
|
|
}
|
|
|
|
button {
|
|
font: inherit;
|
|
color: inherit;
|
|
}
|
|
|
|
:where(a, button, input, textarea, select, [tabindex]):focus-visible {
|
|
outline: 2px solid var(--c-focus);
|
|
outline-offset: 2px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* --- primitivas de layout ------------------------------------------------ */
|
|
|
|
.container {
|
|
width: 100%;
|
|
max-width: var(--container);
|
|
margin-inline: auto;
|
|
padding-inline: var(--sp-4);
|
|
}
|
|
|
|
.stack > * + * {
|
|
margin-top: var(--sp-4);
|
|
}
|
|
|
|
.muted {
|
|
color: var(--c-text-muted);
|
|
}
|
|
|
|
.eyebrow {
|
|
font-size: var(--fs-xs);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--c-text-muted);
|
|
margin: 0 0 var(--sp-2);
|
|
}
|
|
|
|
.visually-hidden {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
padding: 0;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
clip-path: inset(50%);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--sp-2);
|
|
padding: var(--boton-relleno);
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-boton);
|
|
/*
|
|
* `background-color` y no el atajo `background`: el atajo reinicia también
|
|
* `background-image`, así que una variante con degradado —el botón dorado—
|
|
* lo perdía en cuanto esta regla o la de `:hover` se aplicaban, y se quedaba
|
|
* en un rectángulo oscuro con el borde de oro.
|
|
*/
|
|
background-color: transparent;
|
|
font-size: var(--boton-texto);
|
|
letter-spacing: 0.01em;
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
line-height: 1.2;
|
|
transition:
|
|
background-color 0.2s var(--suave),
|
|
border-color 0.2s var(--suave);
|
|
}
|
|
|
|
/*
|
|
* El botón secundario acusa el puntero con el fondo y el canto, no con el
|
|
* color del texto: teñirlo de dorado además sería una señal doble, y encima
|
|
* competiría con el botón dorado que suele tener al lado. El color se declara
|
|
* aquí para ganarle a la regla general de los enlaces, ya que muchos de estos
|
|
* botones lo son.
|
|
*/
|
|
.btn:hover {
|
|
background-color: var(--c-bg-raised);
|
|
border-color: var(--c-text-muted);
|
|
color: inherit;
|
|
}
|
|
|
|
/*
|
|
* El aspecto dorado, aparte del botón que lo estrenó.
|
|
*
|
|
* Lo lleva también el conmutador de vista de la página de música, que no es un
|
|
* `.btn` —va dentro de una barra y no puede tener canto ni esquinas propias—
|
|
* pero sí tiene que ser el mismo oro. Copiarlo era garantizar que un día uno de
|
|
* los dos se quedara plano.
|
|
*/
|
|
.btn--primary,
|
|
.oro {
|
|
/* El color plano queda de reserva: si el degradado no se pintara, el botón
|
|
sigue siendo dorado y legible, no transparente. */
|
|
background-color: var(--c-accent-superficie);
|
|
background-image: var(--oro);
|
|
background-size: 100% 240%;
|
|
background-position: 0 22%;
|
|
color: var(--c-accent-text);
|
|
/* El filo de luz de arriba. Sin él, el degradado se ve pintado, no biselado. */
|
|
box-shadow: inset 0 1px 0 color-mix(in oklab, white 45%, transparent);
|
|
transition:
|
|
background-position 0.6s var(--sal),
|
|
border-color 0.2s var(--suave);
|
|
}
|
|
|
|
/* El canto sí es del botón: dentro de una barra no hay borde que teñir. */
|
|
.btn--primary {
|
|
border-color: var(--c-accent-sombra);
|
|
}
|
|
|
|
/*
|
|
* Al acercar el puntero, la luz recorre la pieza. El color de fondo se repite
|
|
* aquí porque `.btn:hover` lo cambia por el gris de los botones normales: sin
|
|
* esto, un dorado que no llegara a pintar el degradado se vería oscuro.
|
|
*/
|
|
.btn--primary:hover,
|
|
.oro:hover {
|
|
background-color: var(--c-accent-superficie);
|
|
background-position: 0 78%;
|
|
border-color: var(--c-accent);
|
|
/*
|
|
* El color se repite aquí porque `.btn:hover` lo pone en `inherit` —para
|
|
* que la regla general de los enlaces no tiña de dorado los secundarios— y
|
|
* le gana por especificidad. Sin esta línea, el texto del botón dorado se
|
|
* aclaraba al pasar el puntero y quedaba en 1,67 de contraste sobre el oro.
|
|
*/
|
|
color: var(--c-accent-text);
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.btn--primary,
|
|
.oro {
|
|
transition: none;
|
|
}
|
|
}
|
|
|
|
/* --- etiquetas -----------------------------------------------------------
|
|
*
|
|
* La pastilla de una etiqueta. Estaba repetida en cinco sitios con cinco copias
|
|
* del mismo borde redondeado, y se escribe una vez.
|
|
*
|
|
* Va aquí y no en un componente porque a veces es un enlace —lleva a lo que
|
|
* agrupa— y a veces es solo texto: dentro de una tarjeta que ya es clicable,
|
|
* meter enlaces dentro de otro enlace deja una zona donde el clic hace una cosa
|
|
* distinta según el píxel exacto.
|
|
*/
|
|
.chips {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--sp-2);
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.chip {
|
|
display: inline-block;
|
|
padding: 0.2em 0.7em;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-boton);
|
|
font-size: var(--fs-xs);
|
|
color: var(--c-text-muted);
|
|
text-decoration: none;
|
|
transition:
|
|
border-color 0.3s var(--suave),
|
|
color 0.3s var(--suave);
|
|
}
|
|
|
|
a.chip:hover,
|
|
a.chip:focus-visible {
|
|
border-color: var(--c-accent);
|
|
color: var(--c-text);
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.chip {
|
|
transition: none;
|
|
}
|
|
}
|
|
|
|
/* --- tarjetas ------------------------------------------------------------ */
|
|
|
|
/*
|
|
* El comportamiento de las tarjetas (aparición al entrar en pantalla y
|
|
* respuesta al puntero) vive aquí y no en cada componente: son tres tipos de
|
|
* tarjeta —estilo, álbum y canción— y tenían que moverse igual. Al ser CSS
|
|
* global no hace falta pelearse con el ámbito de Svelte para los atributos que
|
|
* escribe la acción `revelar` en tiempo de ejecución.
|
|
*
|
|
* Sobre el movimiento: nada usa `ease`, que es la curva por defecto y se nota
|
|
* como tal —arranca y frena igual, y todo acaba pareciéndose—. Aquí se sale
|
|
* rápido y se frena largo, que es como se mueve algo que pesa.
|
|
*/
|
|
.tarjeta {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-tarjeta);
|
|
background: var(--c-bg-raised);
|
|
overflow: hidden;
|
|
isolation: isolate;
|
|
transition:
|
|
transform 0.55s var(--sal),
|
|
border-color 0.4s var(--suave),
|
|
box-shadow 0.55s var(--sal);
|
|
}
|
|
|
|
/*
|
|
* El reflejo. Nace donde está el puntero —lo escribe la acción `brillo` en
|
|
* `--mx` y `--my`— y por eso no se lee como un efecto enlatado. Sin JavaScript
|
|
* las variables no existen y cae arriba en el centro, que es un valor
|
|
* razonable, no un fallo.
|
|
*/
|
|
.tarjeta::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 0;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
background: radial-gradient(
|
|
20rem 20rem at var(--mx, 50%) var(--my, 0%),
|
|
color-mix(in oklab, var(--c-accent) 20%, transparent),
|
|
transparent 70%
|
|
);
|
|
transition: opacity 0.45s var(--suave);
|
|
}
|
|
|
|
.tarjeta:hover::before,
|
|
.tarjeta:focus-within::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
/*
|
|
* Aparición al entrar en pantalla, para cualquier elemento con la acción
|
|
* `revelar`. Vive aquí y no en cada componente por dos motivos: lo usan las
|
|
* tarjetas y también las listas del taller, y sobre todo porque el atributo lo
|
|
* escribe la acción en tiempo de ejecución, así que el compilador de Svelte no
|
|
* lo ve en el marcado y podaría la regla como si no se usara.
|
|
*
|
|
* El estado oculto lo pone la acción, nunca el CSS por su cuenta: sin
|
|
* JavaScript no hay atributo y todo se ve directamente.
|
|
*/
|
|
[data-revelar='oculto'] {
|
|
opacity: 0;
|
|
transform: translateY(18px) scale(0.985);
|
|
}
|
|
|
|
[data-revelar='visible'] {
|
|
animation: revelarse 0.8s var(--sal) var(--retraso-revelado, 0ms) both;
|
|
}
|
|
|
|
@keyframes revelarse {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(18px) scale(0.985);
|
|
filter: blur(6px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: none;
|
|
filter: blur(0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Al acercarse, la tarjeta sube y se le enciende el borde en dorado. La sombra
|
|
* va en dos capas —una corta y densa, otra larga y difusa—: una sola sombra
|
|
* grande se ve como una mancha, y en dos parece que hay algo debajo.
|
|
*/
|
|
.tarjeta:hover,
|
|
.tarjeta:focus-within {
|
|
transform: translateY(-6px);
|
|
border-color: color-mix(in oklab, var(--c-accent) 55%, var(--c-border));
|
|
box-shadow:
|
|
0 2px 8px -4px rgb(0 0 0 / 0.5),
|
|
0 24px 48px -28px rgb(0 0 0 / 0.85);
|
|
}
|
|
|
|
/* Al pulsar, la tarjeta cede. Sin esto el clic no se siente en ninguna parte. */
|
|
.tarjeta:active {
|
|
transform: translateY(-2px) scale(0.994);
|
|
transition-duration: 0.12s;
|
|
}
|
|
|
|
.tarjeta__medio {
|
|
position: relative;
|
|
aspect-ratio: 1;
|
|
overflow: hidden;
|
|
background: var(--c-bg-sunken);
|
|
}
|
|
|
|
.tarjeta__medio--ancho {
|
|
aspect-ratio: 16 / 10;
|
|
}
|
|
|
|
/*
|
|
* En reposo la portada está un punto apagada y vuelve a su color al acercarse.
|
|
* Es lo que hace destacar a la tarjeta señalada sin tener que atenuar el resto.
|
|
*/
|
|
.tarjeta__medio img {
|
|
/*
|
|
* En una variable por lo mismo que el desenfoque de la cabecera: escrito
|
|
* directamente, el minificador deja `saturate(.85)brightness(.92)` sin el
|
|
* espacio que separa las dos funciones, y eso no es CSS válido.
|
|
*/
|
|
--apagado: saturate(0.85) brightness(0.92);
|
|
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
filter: var(--apagado);
|
|
transform: scale(1.01);
|
|
transition:
|
|
transform 0.7s var(--sal),
|
|
filter 0.5s var(--suave);
|
|
}
|
|
|
|
.tarjeta:hover .tarjeta__medio img,
|
|
.tarjeta:focus-within .tarjeta__medio img {
|
|
filter: none;
|
|
transform: scale(1.06);
|
|
}
|
|
|
|
/* Sombra al pie de la portada, para que el cuerpo no arranque de golpe. */
|
|
.tarjeta__medio::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: auto 0 0;
|
|
height: 45%;
|
|
pointer-events: none;
|
|
background: linear-gradient(
|
|
to top,
|
|
color-mix(in oklab, var(--c-bg) 70%, transparent),
|
|
transparent
|
|
);
|
|
opacity: 0.7;
|
|
transition: opacity 0.45s var(--suave);
|
|
}
|
|
|
|
.tarjeta:hover .tarjeta__medio::after,
|
|
.tarjeta:focus-within .tarjeta__medio::after {
|
|
opacity: 1;
|
|
}
|
|
|
|
.tarjeta__cuerpo {
|
|
position: relative;
|
|
z-index: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--sp-2);
|
|
flex: 1;
|
|
padding: var(--sp-4);
|
|
}
|
|
|
|
/*
|
|
* Hace clicable la tarjeta entera sin envolverla en un enlace, que dejaría los
|
|
* botones dentro de él: ni sería HTML válido ni se podría usar con teclado.
|
|
*/
|
|
.tarjeta__enlace::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
/*
|
|
* El subrayado del título crece desde la izquierda en vez de aparecer entero.
|
|
* Va con el fondo y no con un borde para poder animar el ancho sin que la línea
|
|
* cambie de sitio ni empuje al texto.
|
|
*/
|
|
.tarjeta__enlace {
|
|
background-image: linear-gradient(var(--c-accent), var(--c-accent));
|
|
background-repeat: no-repeat;
|
|
background-position: 0 100%;
|
|
background-size: 0 1px;
|
|
transition:
|
|
background-size 0.45s var(--sal),
|
|
color 0.3s var(--suave);
|
|
}
|
|
|
|
.tarjeta:hover .tarjeta__enlace,
|
|
.tarjeta:focus-within .tarjeta__enlace {
|
|
color: var(--c-accent);
|
|
background-size: 100% 1px;
|
|
}
|
|
|
|
/* Lo que va sobre la imagen (el botón de reproducir) y aparece al acercarse. */
|
|
.tarjeta__flotante {
|
|
position: absolute;
|
|
right: var(--sp-3);
|
|
bottom: var(--sp-3);
|
|
z-index: 2;
|
|
opacity: 0;
|
|
transform: translateY(10px) scale(0.7);
|
|
transition:
|
|
opacity 0.25s var(--suave),
|
|
transform 0.5s var(--sal);
|
|
}
|
|
|
|
.tarjeta:hover .tarjeta__flotante,
|
|
.tarjeta:focus-within .tarjeta__flotante {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
|
|
/*
|
|
* El botón de una tarjeta va a su propio tamaño, y no al de los botones de
|
|
* página. Medía 48px sobre portadas de 280 —casi una quinta parte de la
|
|
* imagen— y encima cambiaba de proporción según la tarjeta fuera cuadrada o
|
|
* apaisada. Aquí es siempre el mismo, y sigue por encima del mínimo para
|
|
* acertarle con el dedo.
|
|
*/
|
|
/*
|
|
* El selector lleva `.tarjeta` delante a propósito: los estilos del botón
|
|
* vienen de un componente y Svelte les añade su clase de ámbito, así que con
|
|
* menos peso no se aplicarían. Y nada de `:global()`, que aquí no es sintaxis
|
|
* válida —esto es CSS normal— y hace que se descarte la regla entera sin avisar.
|
|
*/
|
|
.tarjeta .tarjeta__flotante button {
|
|
min-width: 2.25rem;
|
|
min-height: 2.25rem;
|
|
width: 2.25rem;
|
|
height: 2.25rem;
|
|
padding: 0;
|
|
}
|
|
|
|
/*
|
|
* En pantallas táctiles no hay puntero que lo revele, y un botón invisible
|
|
* pero pulsable es peor que ninguno: ahí se queda siempre a la vista. Sin
|
|
* puntero tampoco hay reposo que apagar, así que la portada va a su color.
|
|
*/
|
|
@media (hover: none) {
|
|
.tarjeta__flotante {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
|
|
.tarjeta__medio img {
|
|
filter: none;
|
|
transform: none;
|
|
}
|
|
}
|
|
|
|
/* Lo que se apoya sobre la tarjeta y tiene que quedar por encima del enlace. */
|
|
.tarjeta__encima {
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
[data-revelar='visible'] {
|
|
animation: none;
|
|
}
|
|
|
|
.tarjeta,
|
|
.tarjeta::before,
|
|
.tarjeta__medio img,
|
|
.tarjeta__medio::after,
|
|
.tarjeta__enlace,
|
|
.tarjeta__flotante {
|
|
transition: none;
|
|
}
|
|
|
|
.tarjeta:hover,
|
|
.tarjeta:focus-within,
|
|
.tarjeta:active,
|
|
.tarjeta:hover .tarjeta__medio img,
|
|
.tarjeta:focus-within .tarjeta__medio img {
|
|
transform: none;
|
|
}
|
|
|
|
.tarjeta__flotante {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
}
|
|
|
|
/* --- términos del glosario ------------------------------------------------
|
|
*
|
|
* El subrayado punteado es la convención de «esto tiene definición» desde
|
|
* mucho antes que la web, y se distingue de un enlace de verdad: un enlace
|
|
* lleva a otra página, esto abre un globo y te deja donde estabas.
|
|
*
|
|
* Va aquí y no en un componente porque el botón lo escribe el servidor dentro
|
|
* del HTML del capítulo, donde el ámbito de Svelte no llega.
|
|
*/
|
|
.termino {
|
|
border: 0;
|
|
padding: 0;
|
|
background: none;
|
|
font: inherit;
|
|
color: inherit;
|
|
cursor: help;
|
|
text-decoration: underline dotted;
|
|
text-decoration-color: color-mix(in oklab, var(--c-accent) 60%, transparent);
|
|
text-underline-offset: 0.2em;
|
|
text-decoration-thickness: 1px;
|
|
}
|
|
|
|
.termino:hover,
|
|
.termino:focus-visible {
|
|
color: var(--c-accent);
|
|
text-decoration-color: var(--c-accent);
|
|
}
|