Arregla el contraste del botón dorado y unifica la letra de los botones

El texto del botón dorado se aclaraba al pasar el puntero y quedaba en 1,67 de
contraste sobre el oro. La causa no era el color del botón: `.btn:hover` pone
`color: inherit` —para que la regla general de los enlaces no tiña de dorado los
secundarios— y le gana por especificidad. Ahora el dorado repite su color ahí.

De paso, el dorado se parte en dos tokens porque hacía dos trabajos
incompatibles: de relleno tiene que ser claro para que encima se lea el marino
—7,6 de contraste en el tema claro— y escrito tiene que ser hondo para leerse
sobre el fondo —5,3—. Con un solo valor, el tema claro se quedaba en 4,4, por
debajo del mínimo. Y encima del oro va marino, no blanco, en los dos temas.

Los botones tenían tres tamaños distintos: el dorado a 16px con relleno 8/16 y
el de al lado a 14px con 12/24. Dos botones juntos con distinta letra se ven
como un descuido. Ahora hay una sola escala, y los 15px son los del menú.

El botón de ver el carrito solo aparece cuando hay algo dentro, con la cuenta:
uno que lleva a una página vacía gasta el sitio de una llamada a la acción para
decir que no hay nada.

Tres pruebas nuevas lo fijan, incluida la del contraste con el puntero encima,
que es donde estaba el fallo y donde una captura en reposo no lo enseña.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
master
dev 1 month ago
parent a918d55864
commit e929e8c5a9

@ -151,3 +151,62 @@ test.describe('Respuesta al puntero', () => {
expect(fondo).toContain('linear-gradient');
});
});
test.describe('Contraste del dorado', () => {
// 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. Esto lo fija.
const MINIMO = 4.5;
async function contraste(page: import('@playwright/test').Page, selector: string) {
return page
.locator(selector)
.first()
.evaluate((e) => {
const aRgb = (c: string) => {
const x = document.createElement('canvas').getContext('2d')!;
x.fillStyle = c;
x.fillRect(0, 0, 1, 1);
const d = x.getImageData(0, 0, 1, 1).data;
return [d[0], d[1], d[2]];
};
const lum = ([r, g, b]: number[]) => {
const f = (v: number) => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
};
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
};
const s = getComputedStyle(e);
const [a, b] = [lum(aRgb(s.color)), lum(aRgb(s.backgroundColor))].sort((m, n) => n - m);
return (a + 0.05) / (b + 0.05);
});
}
for (const esquema of ['dark', 'light'] as const) {
test(`el botón dorado se lee en tema ${esquema}`, async ({ page }) => {
await page.emulateMedia({ colorScheme: esquema });
await page.goto('/');
expect(await contraste(page, '.btn--primary')).toBeGreaterThan(MINIMO);
// Y también con el puntero encima, que es cuando la banda de luz se
// mueve por debajo del texto.
await page.locator('.btn--primary').first().hover();
expect(await contraste(page, '.btn--primary')).toBeGreaterThan(MINIMO);
});
}
test('todos los botones llevan la misma letra', async ({ page }) => {
// Dos botones juntos con distinto cuerpo se ven como un descuido, y así
// estaban: el dorado a 16px y el de al lado a 14.
await page.goto('/');
const tamanos = await page
.locator('a.btn, button.solido')
.evaluateAll((es) => [
...new Set(es.map((e) => `${getComputedStyle(e).fontSize} ${getComputedStyle(e).padding}`))
]);
expect(tamanos).toHaveLength(1);
});
});

@ -39,6 +39,14 @@
*/
--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);
@ -88,9 +96,9 @@
--oro: linear-gradient(
166deg,
var(--c-accent-sombra) 0%,
var(--c-accent) 24%,
var(--c-accent-superficie) 24%,
var(--c-accent-brillo) 46%,
var(--c-accent) 64%,
var(--c-accent-superficie) 64%,
var(--c-accent-sombra) 100%
);
@ -105,6 +113,20 @@
* 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;
/*
@ -154,10 +176,21 @@
--c-text: oklch(0.24 0.055 264);
--c-text-muted: oklch(0.48 0.038 264);
--c-accent: oklch(0.57 0.125 74);
--c-accent-text: oklch(0.99 0.004 264);
--c-accent-brillo: oklch(0.72 0.14 82);
--c-accent-sombra: oklch(0.44 0.1 66);
/*
* Escrito, el dorado tiene que ser hondo para leerse sobre el blanco:
* 5,3 de contraste. De relleno tiene que ser claro para que encima se lea
* el marino: 7,6. Son dos valores porque son dos trabajos.
*/
--c-accent: oklch(0.52 0.125 74);
--c-accent-superficie: oklch(0.76 0.13 82);
/*
* Marino y no blanco encima del dorado. El blanco daba 4,4 de contraste
* —por debajo del mínimo— y el degradado tiene una banda de luz que lo
* empeora justo donde pasa.
*/
--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);
--c-danger: oklch(0.5 0.17 25);
--c-focus: oklch(0.5 0.13 264);
@ -174,10 +207,11 @@
--c-text: oklch(0.24 0.055 264);
--c-text-muted: oklch(0.48 0.038 264);
--c-accent: oklch(0.57 0.125 74);
--c-accent-text: oklch(0.99 0.004 264);
--c-accent-brillo: oklch(0.72 0.14 82);
--c-accent-sombra: oklch(0.44 0.1 66);
--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);
--c-danger: oklch(0.5 0.17 25);
--c-focus: oklch(0.5 0.13 264);
@ -326,7 +360,7 @@ button {
display: inline-flex;
align-items: center;
gap: var(--sp-2);
padding: var(--sp-3) var(--sp-5);
padding: var(--boton-relleno);
border: 1px solid var(--c-border);
border-radius: var(--radius-boton);
/*
@ -336,7 +370,7 @@ button {
* en un rectángulo oscuro con el borde de oro.
*/
background-color: transparent;
font-size: var(--fs-sm);
font-size: var(--boton-texto);
letter-spacing: 0.01em;
cursor: pointer;
text-decoration: none;
@ -362,7 +396,7 @@ button {
.btn--primary {
/* 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);
background-color: var(--c-accent-superficie);
background-image: var(--oro);
background-size: 100% 240%;
background-position: 0 22%;
@ -381,9 +415,16 @@ button {
* esto, un dorado que no llegara a pintar el degradado se vería oscuro.
*/
.btn--primary:hover {
background-color: var(--c-accent);
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) {

@ -55,11 +55,11 @@
<style>
.boton {
padding: var(--sp-1) var(--sp-3);
padding: var(--boton-relleno);
border: 1px solid var(--c-border);
border-radius: var(--radius-boton);
background: transparent;
font-size: var(--fs-sm);
font-size: var(--boton-texto);
cursor: pointer;
white-space: nowrap;
}
@ -73,8 +73,8 @@
}
.boton.compacto {
font-size: var(--fs-xs);
padding: 2px var(--sp-2);
padding: var(--boton-relleno-corto);
font-size: var(--boton-texto-corto);
}
.estado {

@ -79,13 +79,13 @@
display: inline-flex;
align-items: center;
gap: var(--sp-2);
padding: var(--sp-1) var(--sp-3);
padding: var(--boton-relleno);
border: 1px solid var(--c-border);
border-radius: var(--radius-boton);
background: transparent;
color: var(--c-text-muted);
font: inherit;
font-size: var(--fs-sm);
font-size: var(--boton-texto);
text-decoration: none;
cursor: pointer;
transition:
@ -106,7 +106,8 @@
/* En una esquina no hay sitio para el texto, ni borde que lo enmarque. */
.boton.compacto {
padding: var(--sp-1);
padding: var(--boton-relleno-corto);
font-size: var(--boton-texto-corto);
border: none;
gap: 0;
}

@ -111,8 +111,9 @@
.solido {
/* Con texto ya no es un icono en un círculo, sino un botón. */
border-radius: var(--radius-boton);
padding: var(--sp-2) var(--sp-4);
background-color: var(--c-accent);
padding: var(--boton-relleno);
font-size: var(--boton-texto);
background-color: var(--c-accent-superficie);
background-image: var(--oro);
background-size: 100% 240%;
background-position: 0 22%;
@ -123,7 +124,7 @@
}
.solido:hover:not(:disabled) {
background-color: var(--c-accent);
background-color: var(--c-accent-superficie);
background-position: 0 78%;
border-color: var(--c-accent);
}

@ -9,6 +9,38 @@
let menuAbierto = $state(false);
let cabecera = $state<HTMLElement | null>(null);
/**
* Si la página se ha movido del todo arriba.
*
* Arriba del todo, la cabecera se aparta y deja ver la portada por debajo:
* es lo que hace que la primera pantalla llegue hasta el borde en vez de
* empezar bajo una franja. En cuanto se baja, se vuelve opaca, porque
* entonces lo que pasa por detrás es texto y el menú tiene que seguir
* leyéndose.
*/
let desplazada = $state(false);
$effect(() => {
let pendiente = 0;
function mirar() {
if (pendiente) return;
pendiente = requestAnimationFrame(() => {
pendiente = 0;
// Un umbral pequeño y no cero: con cero, el rebote de algunos
// navegadores la haría parpadear al llegar arriba.
desplazada = window.scrollY > 8;
});
}
mirar();
addEventListener('scroll', mirar, { passive: true });
return () => {
cancelAnimationFrame(pendiente);
removeEventListener('scroll', mirar);
};
});
/**
* La cabecera publica su altura real en `--altura-cabecera`.
*
@ -51,7 +83,7 @@
});
</script>
<header class="cabecera" bind:this={cabecera}>
<header class="cabecera" class:desplazada bind:this={cabecera}>
<div class="container fila">
<a class="marca" href={resolve('/')}>{site.nombre}</a>
@ -134,7 +166,26 @@
position: sticky;
top: 0;
z-index: 30;
background: color-mix(in oklab, var(--c-bg) 68%, transparent);
/*
* Arriba del todo no tapa: solo una sombra suave de arriba abajo para
* que el menú se lea sobre lo que haya detrás. Sin ella, un fotograma
* claro del fondo se comería el texto.
*/
background-image: linear-gradient(
to bottom,
color-mix(in oklab, var(--c-bg) 55%, transparent),
transparent
);
background-color: transparent;
transition:
background-color 0.35s var(--suave),
backdrop-filter 0.35s var(--suave);
}
/* Al bajar, detrás pasa texto: la cabecera se vuelve opaca y desenfoca. */
.cabecera.desplazada {
background-image: none;
background-color: color-mix(in oklab, var(--c-bg) 82%, transparent);
backdrop-filter: var(--desenfoque);
}
@ -144,8 +195,8 @@
* del menú.
*/
@supports not (backdrop-filter: blur(1px)) {
.cabecera {
background: color-mix(in oklab, var(--c-bg) 94%, transparent);
.cabecera.desplazada {
background-color: color-mix(in oklab, var(--c-bg) 96%, transparent);
}
}
@ -229,6 +280,12 @@
cursor: pointer;
}
@media (prefers-reduced-motion: reduce) {
.cabecera {
transition: none;
}
}
@media (max-width: 56rem) {
/*
* Con el menú abierto la cabecera crece; en una pantalla baja podría no

@ -1,5 +1,6 @@
<script lang="ts">
import { resolve } from '$app/paths';
import { page } from '$app/state';
import BotonReproducir from '$lib/components/BotonReproducir.svelte';
import Carrusel, { type Lamina } from '$lib/components/Carrusel.svelte';
import Heroe from '$lib/components/Heroe.svelte';
@ -22,6 +23,9 @@
{ id: 'packs', etiqueta: 'Comprar canciones' }
];
/* Con `?.`: en una página de error el layout puede no haberse ejecutado. */
const enCarrito = $derived(page.data.carrito?.length ?? 0);
const principal = $derived(data.bloquePrincipal);
const pistasPrincipal = $derived(
principal ? aPistas(principal.albumes.flatMap((a) => a.canciones)) : []
@ -69,7 +73,14 @@
>
{#snippet acciones()}
<a class="btn btn--primary" href={resolve('/musica')}>Elegir canciones</a>
<a class="btn" href={resolve('/carrito')}>Ver el carrito</a>
<!--
El carrito solo se ofrece cuando hay algo dentro. Un botón que
lleva a una página vacía no invita a nada: gasta el sitio de una
llamada a la acción para decir «aquí no hay nada».
-->
{#if enCarrito > 0}
<a class="btn" href={resolve('/carrito')}>Ver el carrito ({enCarrito})</a>
{/if}
{/snippet}
</LaminaCta>
{/if}

@ -145,13 +145,13 @@
input[type='search'] {
width: 100%;
padding: var(--sp-2) var(--sp-3);
padding: var(--boton-relleno);
border: 1px solid var(--c-border);
border-radius: var(--radius-boton);
background: var(--c-bg-sunken);
color: inherit;
font: inherit;
font-size: var(--fs-sm);
font-size: var(--boton-texto);
}
input[type='search']:focus-visible {
@ -167,12 +167,12 @@
}
.vistas button {
padding: var(--sp-2) var(--sp-4);
padding: var(--boton-relleno);
border: none;
background: transparent;
color: var(--c-text-muted);
font: inherit;
font-size: var(--fs-sm);
font-size: var(--boton-texto);
cursor: pointer;
}
@ -182,7 +182,7 @@
}
.vistas button[aria-pressed='true'] {
background: var(--c-accent);
background: var(--c-accent-superficie);
color: var(--c-accent-text);
}

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Como si nada">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Como si nada</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">Canción</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 524 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de El último tren">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">El último tren</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">Canción</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 624 B

After

Width:  |  Height:  |  Size: 530 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Como si nada">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Como si nada</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">2024</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 614 B

After

Width:  |  Height:  |  Size: 520 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Dos orillas">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Dos orillas</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">2022</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 518 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Preludios para piano">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Preludios para piano</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">2023</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 536 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Ruido blanco">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Ruido blanco</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">2021</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 614 B

After

Width:  |  Height:  |  Size: 520 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Sin portada">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Sin portada</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978"></text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 608 B

After

Width:  |  Height:  |  Size: 514 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de La última carta">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">La última carta</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">Canción</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 532 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Singles">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Singles</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">Temas sueltos</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 519 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Tres de la tarde">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Tres de la tarde</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">Canción</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 532 B

@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="600" height="600" role="img" aria-label="Portada provisional de Verano tarde">
<rect width="600" height="600" fill="#141c31"/>
<rect x="10" y="10" width="580" height="580" fill="none" stroke="#2b3554" stroke-width="1"/>
<text x="48" y="296" font-family="Georgia, serif" font-size="46" fill="#eef1f8">Verano tarde</text>
<text x="48" y="342" font-family="system-ui, sans-serif" font-size="20" fill="#d8b978">Canción</text>
<text x="48" y="550" font-family="system-ui, sans-serif" font-size="16" fill="#7c88a5">Portada provisional</text>

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 524 B

Loading…
Cancel
Save

Powered by TurnKey Linux.